Repository :
http://git.fedorahosted.org/cgit/copr.git
On branch : master
---------------------------------------------------------------
commit 44b394434dd61f3c7ceeaa9f8c806e6cc2ca54b8
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Mon Sep 22 16:11:55 2014 +0200
[keygen] adding unittests
---------------------------------------------------------------
.gitignore | 1 +
keygen/__init__.py | 1 +
keygen/requirements.txt | 4 +
keygen/run_tests_coverage.sh | 3 +
keygen/src/copr_keygen/__init__.py | 19 ++-
keygen/src/copr_keygen/logic.py | 19 ++-
.../coprs/logic => keygen/test}/__init__.py | 0
keygen/test/test_handles.py | 93 +++++++++++
keygen/test/test_logic.py | 171 ++++++++++++++++++++
9 files changed, 294 insertions(+), 17 deletions(-)
diff --git a/.gitignore b/.gitignore
index 5352e85..bfa76cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
*.pyc
*.pyo
*.swp
+.coverage
data/
cli/dist/
build/
diff --git a/keygen/__init__.py b/keygen/__init__.py
new file mode 100644
index 0000000..f19a366
--- /dev/null
+++ b/keygen/__init__.py
@@ -0,0 +1 @@
+__author__ = 'vgologuz'
diff --git a/keygen/requirements.txt b/keygen/requirements.txt
index c12bb8d..edd49dd 100644
--- a/keygen/requirements.txt
+++ b/keygen/requirements.txt
@@ -1,3 +1,7 @@
sphinxcontrib-httpdomain
flask
six
+mock
+pytest
+pytest-cov
+
diff --git a/keygen/run_tests_coverage.sh b/keygen/run_tests_coverage.sh
new file mode 100644
index 0000000..d14139c
--- /dev/null
+++ b/keygen/run_tests_coverage.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+PYTHONPATH=./src:$PYTHONPATH python -B -m pytest --cov-report term-missing --cov ./src
diff --git a/keygen/src/copr_keygen/__init__.py b/keygen/src/copr_keygen/__init__.py
index e072a5b..7fcb2a9 100644
--- a/keygen/src/copr_keygen/__init__.py
+++ b/keygen/src/copr_keygen/__init__.py
@@ -93,19 +93,20 @@ def gen_key():
return response
+(a)app.errorhandler(KeygenServiceBaseException)
+def handle_invalid_usage(error):
+ response = Response(error.message,
content_type="text/plain;charset=UTF-8")
+ response.status_code = error.status_code
+ response.data = str(error)
+ return response
+
+
# @app.route('/remove_key', methods=["post"])
# def remove_key():
# raise NotImplementedError()
# query = json.loads(request.data)
# print(repr(query))
# mail = query["name_email"]
-#
-# #cmd = "gpg --with-colons --fingerprint gafoo | awk -F: '$1 ==
"fpr" {print $10;}'"
+## #cmd = "gpg --with-colons --fingerprint gafoo |
+# awk -F: '$1 == "fpr" {print $10;}'"
# #TODO: complete implementation
-
-
-(a)app.errorhandler(KeygenServiceBaseException)
-def handle_invalid_usage(error):
- response = Response(error.message,
content_type="text/plain;charset=UTF-8")
- response.status_code = error.status_code
- return response
diff --git a/keygen/src/copr_keygen/logic.py b/keygen/src/copr_keygen/logic.py
index 2963961..88bcd64 100644
--- a/keygen/src/copr_keygen/logic.py
+++ b/keygen/src/copr_keygen/logic.py
@@ -6,20 +6,23 @@ import tempfile
from .exceptions import GpgErrorException
-def _ensure_passphrase_exist(app, name_email):
+def ensure_passphrase_exist(app, name_email):
""" Need this to tell signd server that `name_email` available in
keyring
Key not protected by passphrase, so we write *something* to passphrase file.
"""
+ def create():
+ with open(location, "w") as handle:
+ handle.write("1")
+ handle.write(os.linesep)
location = os.path.join(app.config["PHRASES_DIR"], name_email)
try:
with open(location) as handle:
- if handle.read():
- pass
+ content = handle.read()
+ if not content:
+ create()
except IOError:
- with open(location, "w") as handle:
- handle.write("1")
- handle.write(os.linesep)
+ create()
def user_exists(app, mail):
@@ -42,7 +45,7 @@ def user_exists(app, mail):
if handle.returncode == 0:
# TODO: validate that we really got exactly one line in stdout
- _ensure_passphrase_exist(app, mail)
+ ensure_passphrase_exist(app, mail)
return True
elif "error reading key" in stderr:
return False
@@ -83,7 +86,7 @@ def create_new_key(
if user_exists(app, name_email):
return
- with tempfile.NamedTemporaryFile(delete=False) as out:
+ with tempfile.NamedTemporaryFile() as out:
out.write(template.format(
key_type="RSA",
key_length=key_length or 2048,
diff --git a/frontend/coprs_frontend/coprs/logic/__init__.py b/keygen/test/__init__.py
similarity index 100%
copy from frontend/coprs_frontend/coprs/logic/__init__.py
copy to keygen/test/__init__.py
diff --git a/keygen/test/test_handles.py b/keygen/test/test_handles.py
new file mode 100644
index 0000000..d81b66f
--- /dev/null
+++ b/keygen/test/test_handles.py
@@ -0,0 +1,93 @@
+import json
+import six
+
+if six.PY3:
+ from unittest import mock
+else:
+ import mock
+
+
+from copr_keygen import app
+from copr_keygen.exceptions import KeygenServiceBaseException
+
+
+def test_ping():
+ """ Simple check for simple handle
+ """
+ with app.test_client() as c:
+ rv = c.get('/ping')
+ assert rv.status_code == 200
+ assert rv.data == "pong\n"
+
+
+json_data = json.dumps({
+ "name_real": "foo_bar",
+ "name_email": "foo_bar(a)example.com"
+})
+json_data_missing_email = json.dumps({"name_real": "foo_bar"})
+json_data_missing_name = json.dumps({"name_email":
"foo_bar(a)example.com"})
+
+
+(a)mock.patch("copr_keygen.create_new_key")
+(a)mock.patch("copr_keygen.user_exists")
+class TestGenKey(object):
+
+ def test_gen_key(self, user_exists, create_new_key):
+ """ Check reactions to different sets of input data
+ """
+ user_exists.return_value = False
+ create_new_key.return_value = None
+
+ with app.test_client() as c:
+ #pass
+ rv = c.post('/gen_key', data=json_data)
+ assert rv.status_code == 201
+
+ rv = c.post('/gen_key', data=None)
+ assert rv.status_code == 400
+ #
+ rv = c.post('/gen_key', data=json_data_missing_email)
+ assert rv.status_code == 400
+ #
+ rv = c.post('/gen_key', data=json_data_missing_name)
+ assert rv.status_code == 400
+
+ def test_gen_key_user_not_exists(self, user_exists, create_new_key):
+ """ Check that key is really created when user not exists
+ """
+ user_exists.return_value = False
+ create_new_key.return_value = None
+
+ with app.test_client() as c:
+ rv = c.post('/gen_key', data=json_data)
+ assert rv.status_code == 201
+
+ assert user_exists.called
+ assert create_new_key.called
+
+ def test_gen_key_with_existing_user(self, user_exists, create_new_key):
+ """ Check that key is not created when user not exists
+ """
+ user_exists.return_value = True
+
+ with app.test_client() as c:
+ rv = c.post('/gen_key', data=json_data)
+ assert rv.status_code == 200
+
+ assert user_exists.called
+ assert not create_new_key.called
+
+ def test_server_error_at_user_exists(self, user_exists, _):
+ user_exists.side_effect = KeygenServiceBaseException()
+
+ with app.test_client() as c:
+ rv = c.post('/gen_key', data=json_data)
+ assert rv.status_code == 500
+
+ def test_server_error_at_create_new_key(self, user_exists, create_new_key):
+ user_exists.return_value = False
+ create_new_key.side_effect = KeygenServiceBaseException()
+
+ with app.test_client() as c:
+ rv = c.post('/gen_key', data=json_data)
+ assert rv.status_code == 500
diff --git a/keygen/test/test_logic.py b/keygen/test/test_logic.py
new file mode 100644
index 0000000..c4b0dc1
--- /dev/null
+++ b/keygen/test/test_logic.py
@@ -0,0 +1,171 @@
+from unittest import TestCase
+import tempfile
+import shutil
+import os
+
+import six
+
+if six.PY3:
+ from unittest import mock
+else:
+ import mock
+
+import pytest
+
+from copr_keygen import app
+from copr_keygen.exceptions import GpgErrorException
+from copr_keygen.logic import ensure_passphrase_exist
+
+import copr_keygen.logic as logic
+
+
+TMP_DIR = tempfile.gettempdir()
+
+TEST_EMAIL = "foobar(a)example.com"
+TEST_NAME = "foobar"
+TEST_KEYLENGTH = 2048
+
+
+class TestEnsurePassphrase(TestCase):
+ def __init__(self, *args, **kwargs):
+ super(TestEnsurePassphrase, self).__init__(*args, **kwargs)
+ self.path = None
+ from copr_keygen import app as mock_app
+
+ self.mock_app = mock_app
+
+ @property
+ def target(self):
+ return os.path.join(self.path, TEST_EMAIL)
+
+ def setUp(self):
+ self.path = tempfile.mkdtemp()
+ self.mock_app.config["PHRASES_DIR"] = self.path
+
+ def tearDown(self):
+ shutil.rmtree(self.path)
+
+ def test_file_creation(self):
+ ensure_passphrase_exist(self.mock_app, TEST_EMAIL)
+
+ assert os.path.exists(self.target)
+ assert os.path.getsize(self.target) > 0
+
+ def test_add_content_to_empty_file(self):
+ open(self.target, "w").close()
+ assert os.path.getsize(self.target) == 0
+ ensure_passphrase_exist(self.mock_app, TEST_EMAIL)
+ assert os.path.getsize(self.target) > 0
+
+
+def test_ensure_passphrase_exist():
+ path = os.path.join(TMP_DIR, "TEST_GNUPG_PASSPHRASES")
+ os.mkdir(path)
+ try:
+ from copr_keygen import app as mock_app
+
+ mock_app.config["PHRASES_DIR"] = path
+ ensure_passphrase_exist(mock_app, TEST_EMAIL)
+
+ target = os.path.join(path, TEST_EMAIL)
+ assert os.path.exists(target)
+ assert os.path.getsize(target) > 0
+
+ # now we placing empty file
+ os.remove(target)
+ open(target, "w").close()
+ assert os.path.getsize(target) == 0
+ ensure_passphrase_exist(mock_app, TEST_EMAIL)
+ assert os.path.getsize(target) > 0
+
+ except Exception as e:
+ shutil.rmtree(path, ignore_errors=True)
+ raise e
+
+ shutil.rmtree(path, ignore_errors=True)
+
+
+class MockPopenHandle(object):
+ def __init__(self, returncode=None, stdout=None, stderr=None):
+ self.returncode = returncode or 0
+ self.stdout = stdout or "mock stdout"
+ self.stderr = stderr or "mock stderr"
+
+ def communicate(self):
+ return self.stdout, self.stderr
+
+
+(a)mock.patch("copr_keygen.logic.ensure_passphrase_exist")
+(a)mock.patch("copr_keygen.logic.Popen")
+class TestUserExists(TestCase):
+ def test_exists(self, popen, ensure_passphrase):
+ popen.return_value = MockPopenHandle(0)
+ ensure_passphrase.return_value = True
+ assert logic.user_exists(app, TEST_EMAIL)
+
+ def test_not_exists(self, popen, ensure_passphrase):
+ popen.return_value = MockPopenHandle(1, stderr="error reading key")
+ ensure_passphrase.return_value = True
+ assert not logic.user_exists(app, TEST_EMAIL)
+
+ def test_gpg_unknown_err(self, popen, ensure_passphrase):
+ popen.return_value = MockPopenHandle(1)
+ with pytest.raises(GpgErrorException):
+ logic.user_exists(app, TEST_EMAIL)
+
+ def test_popen_unknown_err(self, popen, ensure_passphrase):
+ popen.side_effect = OSError()
+ with pytest.raises(GpgErrorException):
+ logic.user_exists(app, TEST_EMAIL)
+
+
+(a)mock.patch("copr_keygen.logic.user_exists")
+(a)mock.patch("copr_keygen.logic.Popen")
+class TestCreateKey(TestCase):
+ def test_simple_create(self, popen, user_exists):
+ """
+ Check correct key generation.
+ At first user not exist, but after popen call,
+ it exists
+ """
+
+ user_exists_returns = [False, True]
+ user_exists.side_effect = \
+ lambda *args, **kwargs: user_exists_returns.pop(0)
+ popen.return_value = MockPopenHandle(0)
+
+ res = logic.create_new_key(app, TEST_NAME, TEST_EMAIL, TEST_KEYLENGTH)
+ assert res is None
+
+ def test_strange_situation_create(self, popen, user_exists):
+ """
+ After key generation `user_exists` invoked again, and if it doesn't
+ see key it should raise an error
+ """
+
+ user_exists.return_value = False
+ popen.return_value = MockPopenHandle(0)
+
+ with pytest.raises(GpgErrorException):
+ logic.create_new_key(app, TEST_NAME, TEST_EMAIL, TEST_KEYLENGTH)
+
+ def test_skip_creation_for_existing_user(self, popen, user_exists):
+ user_exists.return_value = True
+ logic.create_new_key(app, TEST_NAME, TEST_EMAIL, TEST_KEYLENGTH)
+
+ user_exists.assert_called_once()
+ assert not popen.called
+
+ def test_error_popen(self, popen, user_exists):
+ user_exists.return_value = False
+ popen.side_effect = OSError()
+ with pytest.raises(GpgErrorException):
+ logic.create_new_key(app, TEST_NAME, TEST_EMAIL, TEST_KEYLENGTH)
+
+ def test_error_gpg(self, popen, user_exists):
+ user_exists.return_value = False
+ err_msg = "Error message 123"
+ popen.return_value = MockPopenHandle(1, stderr=err_msg)
+ with pytest.raises(GpgErrorException) as e:
+ logic.create_new_key(app, TEST_NAME, TEST_EMAIL, TEST_KEYLENGTH)
+ assert e.msg == err_msg