Skip to content
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
3 changes: 2 additions & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[bumpversion]
files = setup.py src/HttpLibrary/__init__.py
files = setup.py src/HttpLibrary/__init__.py Makefile
commit = True
tag = True
current_version = 1.1.0

25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
VERSION = 1.1.0

.PHONY: tests
tests:
tox

.PHONY: clean
clean:
git clean -dfx

.PHONY: run-robotframework
run-robotframework:
bin/robotframework tests

.PHONY: buildout-development-py2
buildout-development-py2:
virtualenv --no-site-packages .venv27
.venv27/bin/python bootstrap.py
bin/buildout

.PHONY: buildout-development-py3
buildout-development-py3:
virtualenv --no-site-packages --python=python3 .venv36
.venv36/bin/python bootstrap.py
bin/buildout
7 changes: 7 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ mostly a wrapper supposed to have a nice API)!
Changelog
---------

**v1.0.0**

- Upgraded dependent robotframework library version to 3.1.2(latest).
- Migrated source code to support both python 2 and python 3.
- Unit tests updated accordingly.
- Integrated tox test automation tool to test on multiple python environments.

**v0.4.2**

- Don't enforce ASCII when converting to JSON (so chinese characters are
Expand Down
14 changes: 3 additions & 11 deletions bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
$Id: bootstrap.py 102545 2009-08-06 14:49:47Z chrisw $
"""

import os, shutil, sys, tempfile, urllib2
import os, shutil, sys, tempfile
from optparse import OptionParser

tmpeggs = tempfile.mkdtemp()
Expand All @@ -32,7 +32,7 @@
parser.add_option("-v", "--version", dest="version",
help="use a specific zc.buildout version")
parser.add_option("-d", "--distribute",
action="store_true", dest="distribute", default=True,
action="store_true", dest="distribute", default=False,
help="Use Disribute rather than Setuptools.")

options, args = parser.parse_args()
Expand All @@ -49,18 +49,10 @@
try:
import pkg_resources
if not hasattr(pkg_resources, '_distribute'):
to_reload = True
to_reload = False
raise ImportError
except ImportError:
ez = {}
if USE_DISTRIBUTE:
exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py'
).read() in ez
ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
else:
exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
).read() in ez
ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)

if to_reload:
reload(pkg_resources)
Expand Down
20 changes: 3 additions & 17 deletions buildout.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,23 @@ show-picked-versions = true

develop = .

parts = develop-eggs robotframework pylint
parts = develop-eggs robotframework

[develop-eggs]
recipe = zc.recipe.egg
eggs = robotframework-httplibrary

[versions]
robotframework = 2.7.5
robotframework = 3.1.2

[robotframework]
recipe = zc.recipe.egg
eggs =
robotframework == ${versions:robotframework}
future
robotframework-httplibrary
entry-points =
robotframework=rf_httplib_dev_helper:run_cli
libdoc=robot.libdoc:libdoc_cli

arguments = sys.argv[1:]

[pylint]
recipe = zc.recipe.egg
eggs =
pylint
entry-points = pylint=pylint.lint:Run
extra-paths = src/
arguments = [
'--output-format=colorized',
'--reports=n',
'--include-ids=y',
'--disable=E0611,F0401,W0232,E1101,C0103,C0111,I0011',
'HttpLibrary',
] + sys.argv[1:]

4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

CLASSIFIERS = """
Programming Language :: Python
Programming Language :: Python 2.7
Programming Language :: Python 3.6
Topic :: Software Development :: Testing
"""[1:-1]

Expand All @@ -12,7 +14,7 @@

setup(
name='robotframework-httplibrary',
version="0.4.2",
version="1.1.0",
description='Robot Framework keywords for HTTP requests',
long_description=long_description,
author='Filip Noetzel',
Expand Down
98 changes: 82 additions & 16 deletions src/HttpLibrary/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import object, str
from robot.api import logger

from base64 import b64encode
from functools import wraps
from urlparse import urlparse
from urllib.parse import urlparse, parse_qs

import livetest
import sys
from . import livetest
import json
import jsonpointer
import jsonpatch
Expand All @@ -13,7 +18,7 @@
def load_json(json_string):
try:
return json.loads(json_string)
except ValueError, e:
except ValueError as e:
raise ValueError("Could not parse '%s' as JSON: %s" % (json_string, e))


Expand All @@ -25,7 +30,7 @@ def wrapper(self, json_string, *args, **kwargs):
return wrapper


class HTTP:
class HTTP(object):
"""
HttpLibrary for Robot Framework

Expand All @@ -35,7 +40,7 @@ class HTTP:
Pointer, go to http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-00.
"""

ROBOT_LIBRARY_VERSION = "0.4.2"
ROBOT_LIBRARY_VERSION = "1.1.0"

class Context(object):
def __init__(self, http, host=None, scheme='http'):
Expand Down Expand Up @@ -64,7 +69,7 @@ def __init__(self, http, host=None, scheme='http'):
self.post_process_request(None)

def pre_process_request(self):
if len(self.request_headers.items()) > 0:
if len(list(self.request_headers.items())) > 0:
logger.debug("Request headers:")
for name, value in self.request_headers.items():
logger.debug("%s: %s" % (name, value))
Expand Down Expand Up @@ -243,10 +248,10 @@ def POST(self, url):
logger.debug("Performing POST request on %s://%s%s" % (
self.context._scheme, self.app.host, url))
self.context.pre_process_request()
self.context.post_process_request(
self.app.post(path, self.context.request_body or {},
self.context.request_headers, **kwargs)
)
response = self.app.post(path, self.context.request_body or {}, self.context.request_headers, **kwargs)
if path == '/kill' and response.status_int == 200:
return
self.context.post_process_request(response)

def PUT(self, url):
"""
Expand Down Expand Up @@ -324,6 +329,27 @@ def next_request_should_have_status_code(self, status_code=None):
self.context.next_request_should = status_code

# status code
def should_contain_query_params(self, url, expected):

expected_params = json.loads(expected)

parsed_url = urlparse(url, allow_fragments=True)
query = parsed_url.query
fragments = parsed_url.fragment
if sys.version_info[0] == 2:
query = unicode(query)
fragments = unicode(fragments)
parsed_arguments = parse_qs(query)
parsed_arguments.update(parse_qs(fragments))

assert set(parsed_arguments.keys()) == set(expected_params.keys())

for p in list(expected_params):
if expected_params[p] == '':
del expected_params[p]
del parsed_arguments[p]

assert parsed_arguments == expected_params

def get_response_status(self):
"""
Expand Down Expand Up @@ -385,7 +411,14 @@ def get_response_header(self, header_name):
keyword is a list containing both values.
"""
self.response_should_have_header(header_name)
return self.response.headers.getall(header_name)
result = []
if self.get_major_python_version() < 3:
result = self.response.headers.getall(header_name)
else:
for header_val in self.response.headers.getall(header_name)[0].split(","):
result.append(header_val.strip())

return result

def response_header_should_equal(self, header_name, expected):
"""
Expand Down Expand Up @@ -445,6 +478,8 @@ def set_basic_auth(self, username, password):
"""
credentials = "%s:%s" % (username, password)
logger.info('Set basic auth to "%s"' % credentials)
if isinstance(credentials, str):
credentials = credentials.encode()
self.set_request_header(
"Authorization", "Basic %s" % b64encode(credentials))

Expand All @@ -471,7 +506,16 @@ def get_response_body(self):
| ${body}= | Get Response Body | |
| Should Start With | ${body} | <?xml version="1.0" encoding="UTF-8" |
"""
return self.response.body
response_body = self.response.body

# In python2 response comes as str, which satisfies below bytes condition too and fails at decode call.
if isinstance(response_body, str):
return response_body

if isinstance(response_body, bytes):
response_body = response_body.decode('utf-8', 'replace')

return response_body

def response_body_should_contain(self, should_contain):
"""
Expand All @@ -482,10 +526,14 @@ def response_body_should_contain(self, should_contain):
| Response Body Should Contain | version="1.0" |
| Response Body Should Contain | encoding="UTF-8" |
"""
logger.debug('Testing whether "%s" contains "%s".' % (
self.response.body, should_contain))

assert should_contain in self.response.body, \
response = self.response.body
if isinstance(response, bytes):
response = response.decode("utf-8", "replace")

logger.debug('Testing whether "%s" contains "%s".' % (response, should_contain))

assert should_contain in response, \
'"%s" should have contained "%s", but did not.' % (
self.response.body, should_contain)

Expand Down Expand Up @@ -548,7 +596,7 @@ def stringify_json(self, data):

try:
return json.dumps(data, ensure_ascii=False)
except ValueError, e:
except ValueError as e:
raise ValueError(
"Could not stringify '%r' to JSON: %s" % (data, e))

Expand Down Expand Up @@ -630,3 +678,21 @@ def show_response_body_in_browser(self):
This is meant for debugging response body's with complex media types.
"""
self.context.response.showbrowser()

def get_major_python_version(self):
"""
returns the current python version
"""
return sys.version_info[0]

def log_message(self, message, log_level='INFO'):
"""
Logs the message.

Specify `log_level` (default: "INFO") to set the log level.
"""
if message:
logger.write("Message :", log_level)
logger.write(message, log_level)
else:
logger.debug("No message received", log_level)
Loading