From 08a1325b3e19d2c5a520b8cc9c07796d5a46b042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20=C5=9Amiejczak?= Date: Mon, 9 Jan 2017 00:06:16 +0100 Subject: [PATCH] added travis and linter. --- .travis.yml | 12 +++++++++++ pylama.ini | 5 +++++ setup.py | 9 +++++++- src/examples/zap-baseline.py | 4 +--- src/zapv2/__init__.py | 40 ++++++------------------------------ tests/__init__.py | 0 tests/unit/__init__.py | 0 tests/unit/conftest.py | 17 +++++++++++++++ tests/unit/test_client.py | 39 +++++++++++++++++++++++++++++++++++ 9 files changed, 88 insertions(+), 38 deletions(-) create mode 100644 .travis.yml create mode 100644 pylama.ini mode change 100644 => 100755 setup.py create mode 100644 tests/__init__.py create mode 100644 tests/unit/__init__.py create mode 100644 tests/unit/conftest.py create mode 100644 tests/unit/test_client.py diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7c545e6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +sudo: false +language: python +python: + - '2.7' +install: + - pip install -U --force setuptools pip + - ./setup.py develop + - pip install -e '.[tests]' + +script: + - pylama + - py.test diff --git a/pylama.ini b/pylama.ini new file mode 100644 index 0000000..eda6a25 --- /dev/null +++ b/pylama.ini @@ -0,0 +1,5 @@ +[pylama] +linters = pyflakes + +[pylama:doc/conf.py] +skip = 1 diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 index bf38ec5..0998a4d --- a/setup.py +++ b/setup.py @@ -12,7 +12,11 @@ print "You must have setuptools installed to use setup.py. Exiting..." raise SystemExit(1) - +test_requirements = [ + 'mock', + 'pylama', + 'pytest' +] setup( name="python-owasp-zap-v2.4", version="0.0.9.dev1", @@ -39,4 +43,7 @@ 'Intended Audience :: Developers', 'Intended Audience :: Information Technology', 'Programming Language :: Python'], + + tests_require=test_requirements, + extras_require={'tests': test_requirements} ) diff --git a/src/examples/zap-baseline.py b/src/examples/zap-baseline.py index 787037f..8c7eccc 100755 --- a/src/examples/zap-baseline.py +++ b/src/examples/zap-baseline.py @@ -53,7 +53,6 @@ import time import traceback import urllib2 -from datetime import datetime from random import randint from zapv2 import ZAPv2 @@ -277,7 +276,7 @@ def main(argv): # Not running in docker, so start one try: logging.debug ('Pulling ZAP Weekly Docker image') - ls_output = subprocess.check_output(['docker', 'pull', 'owasp/zap2docker-weekly']) + subprocess.check_output(['docker', 'pull', 'owasp/zap2docker-weekly']) except OSError: logging.warning ('Failed to run docker - is it on your path?') sys.exit(3) @@ -350,7 +349,6 @@ def main(argv): logging.debug ('Ajax Spider complete') # Wait for passive scanning to complete - rtc = zap.pscan.records_to_scan logging.debug ('Records to scan...') while (int(zap.pscan.records_to_scan) > 0): logging.debug ('Records to passive scan : ' + zap.pscan.records_to_scan) diff --git a/src/zapv2/__init__.py b/src/zapv2/__init__.py index 54d9e5d..caaa2f3 100644 --- a/src/zapv2/__init__.py +++ b/src/zapv2/__init__.py @@ -47,20 +47,14 @@ from stats import stats from users import users -class ZapError(Exception): - """ - Base ZAP exception. - """ - pass - class ZAPv2(object): """ Client API implementation for integrating with ZAP v2. """ - # base JSON api url base = 'http://zap/JSON/' + # base OTHER api url base_other = 'http://zap/OTHER/' @@ -71,12 +65,12 @@ def __init__(self, proxies={'http': 'http://127.0.0.1:8080', :Parameters: - `proxies`: dictionary of ZAP proxies to use. - + Note that all of the other classes in this directory are generated new ones will need to be manually added to this file """ self.__proxies = proxies - + self.acsrf = acsrf(self) self.ajaxSpider = ajaxSpider(self) self.ascan = ascan(self) @@ -101,17 +95,6 @@ def __init__(self, proxies={'http': 'http://127.0.0.1:8080', self.stats = stats(self) self.users = users(self) - def _expect_ok(self, json_data): - """ - Checks that we have an OK response, else raises an exception. - - :Parameters: - - `json_data`: the json data to look at. - """ - if type(json_data) == type(list()) and json_data[0] == u'OK': - return json_data - raise ZapError(*json_data.values()) - def urlopen(self, *args, **kwargs): """ Opens a url forcing the proxies to be used. @@ -123,18 +106,7 @@ def urlopen(self, *args, **kwargs): kwargs['proxies'] = self.__proxies return urllib.urlopen(*args, **kwargs).read() - def status_code(self, *args, **kwargs): - """ - Open a url forcing the proxies to be used. - - :Parameters: - - `args`: all non-keyword arguments. - - `kwargs`: all other keyword arguments. - """ - kwargs['proxies'] = self.__proxies - return urllib.urlopen(*args, **kwargs).getcode() - - def _request(self, url, get={}): + def _request(self, url, get=None): """ Shortcut for a GET request. @@ -142,7 +114,7 @@ def _request(self, url, get={}): - `url`: the url to GET at. - `get`: the disctionary to turn into GET variables. """ - return json.loads(self.urlopen(url + '?' + urllib.urlencode(get))) + return json.loads(self.urlopen(url + '?' + urllib.urlencode(get or {}))) def _request_other(self, url, get={}): """ @@ -152,4 +124,4 @@ def _request_other(self, url, get={}): - `url`: the url to GET at. - `get`: the disctionary to turn into GET variables. """ - return self.urlopen(url + '?' + urllib.urlencode(get)) + return self.urlopen(url + '?' + urllib.urlencode(get or {})) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py new file mode 100644 index 0000000..7556c93 --- /dev/null +++ b/tests/unit/conftest.py @@ -0,0 +1,17 @@ +from mock import patch +import pytest + +from zapv2 import ZAPv2 + +@pytest.yield_fixture +def zap(): + """ + All tests will be able to share the instance of client with the same settings.""" + yield ZAPv2() + + +@pytest.yield_fixture +def urllib_mock(): + """Fixture create a mock for urllib library.""" + with patch('zapv2.urllib.urlopen') as urllib_mock: + yield urllib_mock diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py new file mode 100644 index 0000000..edb16e7 --- /dev/null +++ b/tests/unit/test_client.py @@ -0,0 +1,39 @@ +""" +Tests related to the main Zap Client class +""" +from mock import call + +TEST_PROXIES = { + 'http': 'http://127.0.0.1:8080', + 'https': 'http://127.0.0.1:8080', +} + + +def test_urlopen_proxies(zap, urllib_mock): + """Check if Zap client passes proxy to urllib call.""" + urllib_mock.return_value.read.return_value = 'contents' + + assert zap.urlopen() == 'contents' + assert urllib_mock.mock_calls[0][2]['proxies'] == TEST_PROXIES + + +def test_request_response(zap, urllib_mock): + """Request method should return a python object from parsed output""" + urllib_mock.return_value.read.return_value = '{"testkey": "testvalue"}' + + assert zap._request('http://allizom.org', {'querykey': 'queryvalue'}) == {'testkey': 'testvalue'} + assert urllib_mock.mock_calls == [ + call('http://allizom.org?querykey=queryvalue', proxies=TEST_PROXIES), + call().read() + ] + + +def test_request_other(zap, urllib_mock): + """_request_other should simply return a retrieved content.""" + urllib_mock.return_value.read.return_value = '{"testkey": "testvalue"}' + + assert zap._request('http://allizom.org', {'querykey': 'queryvalue'}) == {'testkey': 'testvalue'} + assert urllib_mock.mock_calls == [ + call('http://allizom.org?querykey=queryvalue', proxies=TEST_PROXIES), + call().read() + ]