From e7979b18392f4bbe16e7669b3b11b66ee886a5e7 Mon Sep 17 00:00:00 2001 From: mprahl Date: Sat, 5 Nov 2016 13:20:19 -0400 Subject: [PATCH 1/8] Use app variable from tests for consistency --- tests/utils/test_utils_functions.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/utils/test_utils_functions.py b/tests/utils/test_utils_functions.py index 792d0bc..8df133a 100644 --- a/tests/utils/test_utils_functions.py +++ b/tests/utils/test_utils_functions.py @@ -2,6 +2,7 @@ from mock import patch from datetime import timedelta from postmaster.logger import * +import tests.conftest from postmaster.utils import * from postmaster.apiv1.utils import * @@ -217,7 +218,7 @@ def test_get_wtforms_errors(self): This also tests the new_line_to_break Jinja2 filter. The expected return value is an error stating that both the username and password was not provided with a
in between """ - client = app.test_client() + client = tests.conftest.app.test_client() rv = client.post( '/login', data=dict( @@ -230,7 +231,7 @@ def test_get_wtforms_errors(self): def test_account_lockout_from_ui(self): """ Tests that the user gets an account lockout message after 5 failed attempts. """ - client = app.test_client() + client = tests.conftest.app.test_client() for i in range(6): rv = client.post( From ee4ff7d5928f372b264d9b3cccce78f2a72ae168 Mon Sep 17 00:00:00 2001 From: mprahl Date: Sat, 5 Nov 2016 12:59:27 -0400 Subject: [PATCH 2/8] Use BytesIO instead of StringIO for Python 3 compatibility --- postmaster/apiv1/admins.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/postmaster/apiv1/admins.py b/postmaster/apiv1/admins.py index 47ead30..6444c91 100644 --- a/postmaster/apiv1/admins.py +++ b/postmaster/apiv1/admins.py @@ -8,7 +8,7 @@ from flask import request from flask_login import login_required, current_user import pyqrcode -from StringIO import StringIO +from io import BytesIO from postmaster import db from postmaster.models import Admins from postmaster.logger import json_logger @@ -219,9 +219,9 @@ def qrcode(admin_id): 'The following error occurred in qrcode: {0}'.format(str(e))) raise GenericError('The administrator could not be updated') url = pyqrcode.create(admin.get_totp_uri()) - stream = StringIO() + stream = BytesIO() url.svg(stream, scale=5) - return stream.getvalue().encode('utf-8'), 200, { + return stream.getvalue(), 200, { 'Content-Type': 'image/svg+xml', 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', From 96c4c3e342b7ee12682a7fd72867febfc5d7bd1e Mon Sep 17 00:00:00 2001 From: mprahl Date: Sat, 5 Nov 2016 13:02:23 -0400 Subject: [PATCH 3/8] Convert strings for Python 3 compatibility --- postmaster/apiv1/utils.py | 2 +- tests/ad/test_ad_class.py | 6 +- tests/api/test_api_functions.py | 124 ++++++++++++++-------------- tests/utils/test_utils_functions.py | 5 +- tests/views/test_user_functions.py | 14 ++-- 5 files changed, 76 insertions(+), 75 deletions(-) diff --git a/postmaster/apiv1/utils.py b/postmaster/apiv1/utils.py index c70e52d..f882256 100644 --- a/postmaster/apiv1/utils.py +++ b/postmaster/apiv1/utils.py @@ -114,6 +114,6 @@ def get_logs_dict(numLines=50, reverseOrder=False): if reverseOrder: logs = list(reversed(logs)) - return {'items': [loads(log) for log in logs], } + return {'items': [loads(log.decode('utf-8')) for log in logs], } else: raise ValidationError('The log file could not be found') diff --git a/tests/ad/test_ad_class.py b/tests/ad/test_ad_class.py index f7129d3..b84b9c5 100644 --- a/tests/ad/test_ad_class.py +++ b/tests/ad/test_ad_class.py @@ -55,7 +55,7 @@ def test_login_fail(self): @manage_mock_ldap def test_parse_username_input_with_domain(self): - """ Tests the parse_username_input function when the username input is postmaster\username + r""" Tests the parse_username_input function when the username input is postmaster\username """ assert self.ad_obj.parse_username_input('postmaster\\testUser3') == 'postmaster\\testUser3' @@ -88,7 +88,7 @@ def test_search_with_attr(self): assert self.ad_obj.search('(displayName=Test User)', ['name']) == [{ 'attributes': {'name': u'Test User'}, 'dn': 'CN=Test User,OU=PostMaster,DC=postmaster,DC=local', - 'raw_attributes': {'name': ['Test User']}, + 'raw_attributes': {'name': [b'Test User']}, 'type': 'searchResEntry' }] @@ -255,4 +255,4 @@ def test_validate_wtforms_password(self): follow_redirects=True ) - assert '

Dashboard

' in rv.data + assert '

Dashboard

' in rv.data.decode('utf-8') diff --git a/tests/api/test_api_functions.py b/tests/api/test_api_functions.py index e4dc609..2bacaba 100644 --- a/tests/api/test_api_functions.py +++ b/tests/api/test_api_functions.py @@ -13,7 +13,7 @@ class TestMailDbFunctions: def test_aliases_get(self, loggedin_client): rv = loggedin_client.get("/api/v1/aliases", follow_redirects=True) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 200 @@ -22,47 +22,47 @@ def test_aliases_add_fail_domain_managed(self, loggedin_client): rv = loggedin_client.post("/api/v1/aliases", data=json.dumps( {"source": "pickles@test123.com", "destination": "rawr@test123.com"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "not managed" in rv.data + assert "not managed" in rv.data.decode('utf-8') def test_aliases_add_fail_not_current(self, loggedin_client): rv = loggedin_client.post("/api/v1/aliases", data=json.dumps( {"source": "pickles@postmaster.com", "destination": "rawr@postmaster.com"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "not a current" in rv.data + assert "not a current" in rv.data.decode('utf-8') def test_aliases_add_fail_source_empty(self, loggedin_client): rv = loggedin_client.post("/api/v1/aliases", data=json.dumps( {"source": "", "destination": "rawr@postmaster.com"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The source email was not specified" in rv.data + assert "The source email was not specified" in rv.data.decode('utf-8') def test_aliases_add_fail_destination_empty(self, loggedin_client): rv = loggedin_client.post("/api/v1/aliases", data=json.dumps( {"source": "rawr@postmaster.com", "destination": ""})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The destination email was not specified" in rv.data + assert "The destination email was not specified" in rv.data.decode('utf-8') def test_aliases_add_pass(self, loggedin_client): rv = loggedin_client.post("/api/v1/aliases", data=json.dumps( {"source": "rawr@postmaster.com", "destination": "email@postmaster.com"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 201 @@ -81,11 +81,11 @@ def test_alias_update_fail_source_or_destination_not_supplied(self, loggedin_cli rv = loggedin_client.put("/api/v1/aliases/2", data=json.dumps( {"someotherdata": "aomeotherdata"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The source or destination was not supplied in the request" in rv.data + assert "The source or destination was not supplied in the request" in rv.data.decode('utf-8') def test_aliases_delete_pass(self, loggedin_client): rv = loggedin_client.delete("/api/v1/aliases/2", follow_redirects=True) @@ -94,7 +94,7 @@ def test_aliases_delete_pass(self, loggedin_client): def test_users_get(self, loggedin_client): rv = loggedin_client.get("/api/v1/users", follow_redirects=True) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 200 @@ -103,57 +103,57 @@ def test_users_add_fail_not_valid(self, loggedin_client): rv = loggedin_client.post("/api/v1/users", data=json.dumps( {"email": "picklesasda", "password": "som3passw0rd"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "not a valid" in rv.data + assert "not a valid" in rv.data.decode('utf-8') def test_users_add_fail_domain_managed(self, loggedin_client): rv = loggedin_client.post("/api/v1/users", data=json.dumps( {"email": "pickles@test123.com", "password": "som3passw0rd"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "not managed" in rv.data + assert "not managed" in rv.data.decode('utf-8') def test_users_add_fail_password_empty(self, loggedin_client): rv = loggedin_client.post("/api/v1/users", data=json.dumps( {"email": "pickles@test123.com", "password": ""})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The password was not specified" in rv.data + assert "The password was not specified" in rv.data.decode('utf-8') def test_users_add_fail_email_empty(self, loggedin_client): rv = loggedin_client.post("/api/v1/users", data=json.dumps( {"email": "", "password": "som3passw0rd"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The email address was not specified" in rv.data + assert "The email address was not specified" in rv.data.decode('utf-8') def test_users_update_fail_password_not_supplied(self, loggedin_client): rv = loggedin_client.put("/api/v1/users/2", data=json.dumps( {"someotherdata": "pickles"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The password was not supplied in the request" in rv.data + assert "The password was not supplied in the request" in rv.data.decode('utf-8') def test_users_add_pass(self, loggedin_client): rv = loggedin_client.post("/api/v1/users", data=json.dumps( {"email": "pickles@postmaster.com", "password": "som3passw0rd"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 201 @@ -170,7 +170,7 @@ def test_users_delete_pass(self, loggedin_client): def test_domains_get(self, loggedin_client): rv = loggedin_client.get("/api/v1/domains", follow_redirects=True) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 200 @@ -179,37 +179,37 @@ def test_users_add_fail_domain_missing(self, loggedin_client): rv = loggedin_client.post("/api/v1/domains", data=json.dumps( {"lol": "what"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "not specified" in rv.data + assert "not specified" in rv.data.decode('utf-8') def test_domains_add_fail_already_exists(self, loggedin_client): rv = loggedin_client.post("/api/v1/domains", data=json.dumps( {"name": "postmaster.com"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "already exists" in rv.data + assert "already exists" in rv.data.decode('utf-8') def test_domains_add_fail_name_empty(self, loggedin_client): rv = loggedin_client.post("/api/v1/domains", data=json.dumps( {"name": ""})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The domain name was not specified" in rv.data + assert "The domain name was not specified" in rv.data.decode('utf-8') def test_domains_add_pass(self, loggedin_client): rv = loggedin_client.post("/api/v1/domains", data=json.dumps( {"name": "".join((random.choice(string.ascii_uppercase + string.digits) for _ in range(6))) + ".com"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 201 @@ -221,7 +221,7 @@ def test_domains_delete_pass(self, loggedin_client): def test_admins_get_one(self, loggedin_client): rv = loggedin_client.get("/api/v1/admins/1", follow_redirects=True) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 200 @@ -229,7 +229,7 @@ def test_admins_get_one(self, loggedin_client): def test_admins_get_all(self, loggedin_client): rv = loggedin_client.get("/api/v1/admins", follow_redirects=True) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 200 @@ -238,7 +238,7 @@ def test_admins_add_pass(self, loggedin_client): rv = loggedin_client.post("/api/v1/admins", data=json.dumps( {"username": "user_admin@postmaster.com", "password": "som3passw0rd", "name": "Test Admin"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 201 @@ -247,41 +247,41 @@ def test_admins_add_fail_duplicate(self, loggedin_client): rv = loggedin_client.post("/api/v1/admins", data=json.dumps( {"username": "admin", "password": "som3passw0rd", "name": "Test Admin"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "already exists" in rv.data + assert "already exists" in rv.data.decode('utf-8') def test_admins_add_fail_no_username(self, loggedin_client): rv = loggedin_client.post("/api/v1/admins", data=json.dumps( {"password": "som3passw0rd", "name": "Test Admin"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The username was not specified" in rv.data + assert "The username was not specified" in rv.data.decode('utf-8') def test_admins_add_fail_no_password(self, loggedin_client): rv = loggedin_client.post("/api/v1/admins", data=json.dumps( {"username": "user_admin2@postmaster.com", "name": "Test Admin"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The password was not specified" in rv.data + assert "The password was not specified" in rv.data.decode('utf-8') def test_admins_add_fail_no_name(self, loggedin_client): rv = loggedin_client.post("/api/v1/admins", data=json.dumps( {"username": "user_admin2@postmaster.com", "password": "som3passw0rd"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "The name was not specified" in rv.data + assert "The name was not specified" in rv.data.decode('utf-8') def test_admins_update_password_pass(self, loggedin_client): rv = loggedin_client.put("/api/v1/admins/2", data=json.dumps( @@ -302,7 +302,7 @@ def test_admins_update_fail(self, loggedin_client): rv = loggedin_client.put("/api/v1/admins/2", data=json.dumps( {"randomkey": "random_value"})) assert rv.status_code == 400 - assert "The username, password, or name was not supplied in the request" in rv.data + assert "The username, password, or name was not supplied in the request" in rv.data.decode('utf-8') def test_admins_delete_pass(self, loggedin_client): rv = loggedin_client.delete("/api/v1/admins/2", follow_redirects=True) @@ -336,7 +336,7 @@ def test_admins_twofactor_qrcode(self, loggedin_client): def test_admins_twofactor_status(self, loggedin_client): rv = loggedin_client.get("/api/v1/admins/1/twofactor") try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 200 @@ -344,20 +344,20 @@ def test_admins_twofactor_status(self, loggedin_client): def test_admins_twofactor_update_fail(self, loggedin_client): rv = loggedin_client.put("/api/v1/admins/1/twofactor") try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "invalid request" in rv.data + assert "invalid request" in rv.data.decode('utf-8') def test_admins_twofactor_enable_fail(self, loggedin_client): rv = loggedin_client.put("/api/v1/admins/1/twofactor", data=json.dumps({"enabled": "True"})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "Cannot enable 2 factor" in rv.data + assert "Cannot enable 2 factor" in rv.data.decode('utf-8') def test_admins_twofactor_verify_invalid(self, loggedin_client): test_admin = Admins().from_json({ @@ -372,11 +372,11 @@ def test_admins_twofactor_verify_invalid(self, loggedin_client): db.session.commit() rv = loggedin_client.post("/api/v1/admins/{0}/twofactor/verify".format(test_admin.id), data=json.dumps({"code": 123456})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "invalid code" in rv.data + assert "invalid code" in rv.data.decode('utf-8') def test_admins_twofactor_verify_secret_fail(self, loggedin_client): test_admin = Admins().from_json({ @@ -389,11 +389,11 @@ def test_admins_twofactor_verify_secret_fail(self, loggedin_client): db.session.commit() rv = loggedin_client.post("/api/v1/admins/{0}/twofactor/verify".format(test_admin.id), data=json.dumps({"code": 123456})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 400 - assert "2 Factor Secret" in rv.data + assert "2 Factor Secret" in rv.data.decode('utf-8') def test_admins_twofactor_verify_valid(self, loggedin_client): test_admin = Admins().from_json({ @@ -412,7 +412,7 @@ def test_admins_twofactor_verify_valid(self, loggedin_client): assert test_admin.verify_totp(token) rv = loggedin_client.post("/api/v1/admins/{0}/twofactor/verify".format(test_admin.id), data=json.dumps({"code": token})) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 200 @@ -420,7 +420,7 @@ def test_admins_twofactor_verify_valid(self, loggedin_client): def test_configs_get_one(self, loggedin_client): rv = loggedin_client.get("/api/v1/configs/1", follow_redirects=True) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 200 @@ -428,7 +428,7 @@ def test_configs_get_one(self, loggedin_client): def test_configs_get_all(self, loggedin_client): rv = loggedin_client.get("/api/v1/configs", follow_redirects=True) try: - json.loads(rv.data) + json.loads(rv.data.decode('utf-8')) except: assert False, "Not json" assert rv.status_code == 200 @@ -442,7 +442,7 @@ def test_configs_update_fail(self, loggedin_client): rv = loggedin_client.put("/api/v1/configs/5", data=json.dumps( {"someparameter": "somevalue"})) assert rv.status_code == 400 - assert 'An invalid setting value was supplied' in rv.data + assert 'An invalid setting value was supplied' in rv.data.decode('utf-8') @patch('os.access', return_value=False) def test_configs_enable_login_auditing_log_write_fail(self, mock_os_access, loggedin_client): @@ -451,7 +451,7 @@ def test_configs_enable_login_auditing_log_write_fail(self, mock_os_access, logg {"value": "True"})) app.config['LOG_LOCATION'] = '' assert rv.status_code == 400 - assert 'The log could not be written to' in rv.data + assert 'The log could not be written to' in rv.data.decode('utf-8') # Since we have to turn on logging to test this, we'll mock the json_logger so we don't actually write anything @patch('postmaster.logger.json_logger', return_value=None) @@ -468,7 +468,7 @@ def test_configs_enable_maildb_auditing_log_write_fail(self, mock_os_access, log rv = loggedin_client.put("/api/v1/configs/6", data=json.dumps( {"value": "True"})) assert rv.status_code == 400 - assert 'The log could not be written to' in rv.data + assert 'The log could not be written to' in rv.data.decode('utf-8') @patch('os.access', return_value=True) def test_configs_enable_maildb_auditing_log_write_pass(self, mock_os_access, loggedin_client, tmpdir): @@ -489,7 +489,7 @@ def test_configs_min_pwd_update_fail(self, loggedin_client): rv = loggedin_client.put("/api/v1/configs/1", data=json.dumps( {"value": "9999"})) assert rv.status_code == 400 - assert 'An invalid value was supplied. The value must be between 0-25.' in rv.data + assert 'An invalid value was supplied. The value must be between 0-25.' in rv.data.decode('utf-8') def test_configs_update_enable_ldap_no_server(self, loggedin_client): """ Tests the update_config function (PUT route for configs) when LDAP is set to enabled @@ -511,7 +511,7 @@ def test_configs_update_enable_ldap_no_server(self, loggedin_client): db.session.commit() assert rv.status_code == 400 - assert 'The LDAP settings must be configured before LDAP authentication is enabled' in rv.data + assert 'The LDAP settings must be configured before LDAP authentication is enabled' in rv.data.decode('utf-8') def test_configs_update_empty_ldap_server_when_ldap_enabled(self, loggedin_client): """ Tests the update_config function (PUT route for configs) when the LDAP server is set to empty @@ -533,4 +533,4 @@ def test_configs_update_empty_ldap_server_when_ldap_enabled(self, loggedin_clien db.session.commit() assert rv.status_code == 400 - assert 'LDAP authentication must be disabled when deleting LDAP configuration items' in rv.data + assert 'LDAP authentication must be disabled when deleting LDAP configuration items' in rv.data.decode('utf-8') diff --git a/tests/utils/test_utils_functions.py b/tests/utils/test_utils_functions.py index 8df133a..655d628 100644 --- a/tests/utils/test_utils_functions.py +++ b/tests/utils/test_utils_functions.py @@ -226,7 +226,8 @@ def test_get_wtforms_errors(self): ), follow_redirects=True ) - assert 'The username was not provided
The password was not provided' in rv.data + assert 'The username was not provided
The password was not provided' in rv.data.decode('utf-8') or \ + 'The password was not provided
The username was not provided' in rv.data.decode('utf-8') def test_account_lockout_from_ui(self): """ Tests that the user gets an account lockout message after 5 failed attempts. @@ -244,4 +245,4 @@ def test_account_lockout_from_ui(self): follow_redirects=True ) - assert 'The user is currently locked out. Please try logging in again later.' in rv.data + assert 'The user is currently locked out. Please try logging in again later.' in rv.data.decode('utf-8') diff --git a/tests/views/test_user_functions.py b/tests/views/test_user_functions.py index f8f8340..8e89a47 100644 --- a/tests/views/test_user_functions.py +++ b/tests/views/test_user_functions.py @@ -4,28 +4,28 @@ class TestUserFunctions: def test_user_login(self, loggedin_client): rv = loggedin_client.get("/", follow_redirects=True) - assert "Logout" in rv.data + assert "Logout" in rv.data.decode('utf-8') def test_domains_page(self, loggedin_client): rv = loggedin_client.get("/domains", follow_redirects=True) - assert "Domains" in rv.data + assert "Domains" in rv.data.decode('utf-8') def test_users_page(self, loggedin_client): rv = loggedin_client.get("/users", follow_redirects=True) - assert "Users" in rv.data + assert "Users" in rv.data.decode('utf-8') def test_aliases_page(self, loggedin_client): rv = loggedin_client.get("/aliases", follow_redirects=True) - assert "Aliases" in rv.data + assert "Aliases" in rv.data.decode('utf-8') def test_admins_page(self, loggedin_client): rv = loggedin_client.get("/admins", follow_redirects=True) - assert "Administrators" in rv.data + assert "Administrators" in rv.data.decode('utf-8') def test_configs_page(self, loggedin_client): rv = loggedin_client.get("/admins", follow_redirects=True) - assert "Administrators" in rv.data + assert "Administrators" in rv.data.decode('utf-8') def test_user_logout(self, loggedin_client): rv = loggedin_client.get("/logout", follow_redirects=True) - assert "Successfully logged out" in rv.data + assert "Successfully logged out" in rv.data.decode('utf-8') From abf7f66fcb4a70617a56dc8e13a1660f5cd4dc59 Mon Sep 17 00:00:00 2001 From: mprahl Date: Fri, 11 Nov 2016 22:06:57 -0500 Subject: [PATCH 4/8] Cast exception values as strings for message comparison --- tests/ad/test_ad_class.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ad/test_ad_class.py b/tests/ad/test_ad_class.py index b84b9c5..a8e856b 100644 --- a/tests/ad/test_ad_class.py +++ b/tests/ad/test_ad_class.py @@ -51,7 +51,7 @@ def test_login_fail(self): """ with pytest.raises(postmaster.ad.ADException) as excinfo: self.ad_obj.login('user', 'WrongPassword') - assert excinfo.value.message == 'The username or password was incorrect' + assert str(excinfo.value) == 'The username or password was incorrect' @manage_mock_ldap def test_parse_username_input_with_domain(self): @@ -220,7 +220,7 @@ def test_check_group_membership_pass_primary_group(self): assert self.ad_obj.login( 'CN=testUser2,OU=PostMaster,DC=postmaster,DC=local', 'P@ssW0rd') is True with patch('postmaster.ad.AD.check_nested_group_membership', return_value=False): - assert self.ad_obj.check_group_membership() is True + assert self.ad_obj.check_group_membership() is True @manage_mock_ldap def test_check_group_membership_fail(self): @@ -232,7 +232,7 @@ def test_check_group_membership_fail(self): with patch('postmaster.ad.AD.check_nested_group_membership', return_value=False): with pytest.raises(postmaster.ad.ADException) as excinfo: self.ad_obj.check_group_membership() - assert excinfo.value.message == 'The user account is not authorized to login to PostMaster' + assert str(excinfo.value) == 'The user account is not authorized to login to PostMaster' @manage_mock_ldap def test_validate_wtforms_password(self): From 040dd93de215d39666f06eb202a3d657130a95e1 Mon Sep 17 00:00:00 2001 From: mprahl Date: Fri, 11 Nov 2016 22:10:13 -0500 Subject: [PATCH 5/8] Add Python 3.4 and 3.5 testing to TravisCI --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 531c362..d24a9b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: python python: - - "2.7" + - 2.7 + - 3.4 + - 3.5 install: - cp config.default.py config.py - pip install -r requirements.txt From 38d2f4550d5e7b3d1dac10f26bc40c109d9bf97b Mon Sep 17 00:00:00 2001 From: mprahl Date: Fri, 11 Nov 2016 22:24:14 -0500 Subject: [PATCH 6/8] Remove unnecessary command run in TravisCI --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d24a9b5..855d402 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ install: before_script: - ./pylint-check.py script: - - mkdir -p ../logs - py.test -v --cov postmaster --cov-report term-missing tests/ after_success: - coveralls From 9425af6dfa554edfffee4560a8d06c40bd19e22d Mon Sep 17 00:00:00 2001 From: mprahl Date: Sat, 5 Nov 2016 13:29:40 -0400 Subject: [PATCH 7/8] Add changelog entry --- docs/ChangeLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index ca80af3..e4f3135 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -14,6 +14,7 @@ Features: Improvements: * Replaced GIF spinner with a pure CSS spinner using CSS3 animations [GH-177]. +* Adds Python 3.5 support [GH-179] [GH-180] ### v1.1.0 - A Hard Day's Night From 371227851c8003ea77da001544ee0858bee40f82 Mon Sep 17 00:00:00 2001 From: mprahl Date: Fri, 11 Nov 2016 22:39:36 -0500 Subject: [PATCH 8/8] Add Python 3.5 badge to the readme --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a337fa3..10c84aa 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -## PostMaster [![Build Status](https://travis-ci.org/StackFocus/PostMaster.svg?branch=master)](https://travis-ci.org/StackFocus/PostMaster) ![Python](https://img.shields.io/badge/python-2.7-blue.svg) ![Flask](http://flask.pocoo.org/static/badges/made-with-flask-s.png) +## PostMaster [![Build Status](https://travis-ci.org/StackFocus/PostMaster.svg?branch=master)](https://travis-ci.org/StackFocus/PostMaster) ![Python 2.7](https://img.shields.io/badge/python-2.7-blue.svg) ![Python 3.5](https://img.shields.io/badge/python-3.5-blue.svg) ![Flask](http://flask.pocoo.org/static/badges/made-with-flask-s.png) ### Overview