From a881ff938c2e3e7a0afbeaa22545000bc0663f83 Mon Sep 17 00:00:00 2001
From: Sascha Herzinger <sascha.herzinger@uni.lu>
Date: Wed, 9 Nov 2016 15:11:02 +0100
Subject: [PATCH] a lot

---
 fractalis/__init__.py                        |  19 +--
 fractalis/analytics/controllers.py           |   8 +-
 fractalis/analytics/job.py                   |  24 +++-
 fractalis/analytics/scripts/test/__init.py__ |   0
 fractalis/analytics/scripts/test/sample.py   |   5 +
 fractalis/celery.py                          |  12 +-
 fractalis/config.py                          |  69 ++---------
 fractalis/session.py                         |  56 +++++++--
 run.py                                       |   4 -
 setup.py                                     |   4 +-
 tests/test_analytics.py                      |  56 +++++----
 tests/test_celery.py                         |  11 +-
 tests/test_config.py                         |  38 ------
 tests/test_job.py                            |  41 ++++---
 tests/test_session.py                        | 116 ++++++++++---------
 15 files changed, 227 insertions(+), 236 deletions(-)
 create mode 100644 fractalis/analytics/scripts/test/__init.py__
 delete mode 100644 run.py
 delete mode 100644 tests/test_config.py

diff --git a/fractalis/__init__.py b/fractalis/__init__.py
index 92c563f..28ea54f 100644
--- a/fractalis/__init__.py
+++ b/fractalis/__init__.py
@@ -5,18 +5,19 @@ Modules in this package:
 """
 from flask import Flask
 
-from fractalis.config import configure_app
 from fractalis.session import RedisSessionInterface
 from fractalis.celery import init_celery
-from fractalis.analytics.controllers import analytics
+from fractalis.analytics.controllers import analytics_blueprint
 
 
-flask_app = Flask(__name__)
-configure_app(flask_app)
+app = Flask(__name__)
+app.config.from_object('fractalis.config')
+app.session_interface = RedisSessionInterface(app.config)
+celery_app = init_celery(app)
 
-flask_app.session_interface = RedisSessionInterface(
-    redis_db_path=flask_app.config['REDIS_DB_PATH'])
+app.register_blueprint(analytics_blueprint, url_prefix='/analytics')
 
-celery_app = init_celery(flask_app)
-
-flask_app.register_blueprint(analytics, url_prefix='/analytics')
+if __name__ == '__main__':
+    app.config.from_envvar('FRACTALIS_CONFIG')
+    celery_app.worker_main(['worker', '--loglevel=DEBUG'])
+    app.run()
diff --git a/fractalis/analytics/controllers.py b/fractalis/analytics/controllers.py
index fcc9794..a06a255 100644
--- a/fractalis/analytics/controllers.py
+++ b/fractalis/analytics/controllers.py
@@ -4,20 +4,20 @@ import uuid
 from flask import Blueprint
 
 
-analytics = Blueprint('analytics', __name__)
+analytics_blueprint = Blueprint('analytics_blueprint', __name__)
 
 
-@analytics.route('', methods=['POST'])
+@analytics_blueprint.route('', methods=['POST'])
 def create_job():
     body = json.dumps({'job_id': str(uuid.uuid4())})
     return body, 201
 
 
-@analytics.route('/<uuid:job_id>', methods=['GET'])
+@analytics_blueprint.route('/<uuid:job_id>', methods=['GET'])
 def get_job_details(job_id):
     pass
 
 
-@analytics.route('/<uuid:job_id>', methods=['DELETE'])
+@analytics_blueprint.route('/<uuid:job_id>', methods=['DELETE'])
 def cancel_job(job_id):
     pass
diff --git a/fractalis/analytics/job.py b/fractalis/analytics/job.py
index 9db3ff5..e0fdff5 100644
--- a/fractalis/analytics/job.py
+++ b/fractalis/analytics/job.py
@@ -1,15 +1,27 @@
-from fractalis import celery_app
+"""
 
+"""
 
-def create_job(script, arguments):
-    pass
 
+def get_celery_task(script):
+    split = script.split('.')
+    module = 'fractalis.analytics.scripts.{}'.format(
+        '.'.join(split[:-1]))
+    exec('import {}'.format(module))
+    celery_task = eval('{}.{}'.format(module, split[-1]))
+    return celery_task
 
-def cancel_job(job_id):
-    pass
+
+def start_job(script, arguments):
+    celery_task = get_celery_task(script)
+    async_result = celery_task.delay(**arguments)
+    return async_result.id
 
 
-def get_job_details(job_id):
+def cancel_job(script, job_id):
     pass
 
 
+def get_job_result(script, job_id):
+    celery_task = get_celery_task(script)
+    return celery_task.AsyncResult(job_id)
diff --git a/fractalis/analytics/scripts/test/__init.py__ b/fractalis/analytics/scripts/test/__init.py__
new file mode 100644
index 0000000..e69de29
diff --git a/fractalis/analytics/scripts/test/sample.py b/fractalis/analytics/scripts/test/sample.py
index 0c3357b..f80b1ed 100644
--- a/fractalis/analytics/scripts/test/sample.py
+++ b/fractalis/analytics/scripts/test/sample.py
@@ -11,3 +11,8 @@ def add(a, b):
 @celery_app.task
 def do_nothing(time):
     sleep(time)
+
+
+@celery_app.task
+def div(a, b):
+    return a / b
diff --git a/fractalis/celery.py b/fractalis/celery.py
index 062e3f4..8ff88cf 100644
--- a/fractalis/celery.py
+++ b/fractalis/celery.py
@@ -27,7 +27,17 @@ def init_celery(app):
     try:
         celery.connection().heartbeat_check()
     except Exception as e:
-        error_msg = "Could not establish connection to {}".format(
+        error_msg = "Could not establish connection to broker: {}".format(
+            app.config['CELERY_BROKER_URL'])
+        raise ConnectionRefusedError(error_msg) from e
+
+    try:
+        @celery.task
+        def f():
+            pass
+        f.delay()
+    except Exception as e:
+        error_msg = "Could not establish connection to backend: {}".format(
             app.config['CELERY_BROKER_URL'])
         raise ConnectionRefusedError(error_msg) from e
 
diff --git a/fractalis/config.py b/fractalis/config.py
index 9999c5a..1020034 100644
--- a/fractalis/config.py
+++ b/fractalis/config.py
@@ -1,62 +1,11 @@
-"""This module manages the configuration of the Fractalis flask app.
-
-Exports:
-    - configure_app -- Function that configures given Flask app
+""" This file contains the default settings for Fractalis.
 """
-import os
-
-from redislite import StrictRedis
-
-
-class BaseConfig(object):
-    """Basic configuration that should be used in production."""
-    DEBUG = False
-    TESTING = False
-    REDIS_DB_PATH = os.path.join(os.sep, 'tmp', 'fractalis.db')
-    redis = StrictRedis(REDIS_DB_PATH)
-    CELERY_BROKER_URL = 'redis+socket://{}'.format(redis.socket_file)
-    CELERY_RESULT_BACKEND = 'redis+socket://{}'.format(redis.socket_file)
-
-
-class DevelopmentConfig(BaseConfig):
-    """Configuration used in development."""
-    DEBUG = True
-    TESTING = False
-
-
-class TestingConfig(BaseConfig):
-    """Configuration used in testing."""
-    DEBUG = False
-    TESTING = True
-
-
-config = {
-    'development': 'fractalis.config.DevelopmentConfig',
-    'testing': 'fractalis.config.TestingConfig',
-    'production': 'fractalis.config.BaseConfig'
-}
-
-
-def configure_app(app, mode=None):
-    """Apply configuration to given flask app based on environment variable.
-
-    This function assumes that the environment variable FRACTALIS_MODE contains
-    the key 'development', 'testing', 'production', or is unset in which case
-    it defaults to 'production'. Each of these keys maps to a class in this
-    module that contains appropriate settings.
-
-    Keyword Arguments:
-    app (Flask) -- An instance of the app to configure
-    mode (string) -- (optional) Use this instead of the environment variable
-
-    Exceptions:
-    KeyError (Exception) -- Is raised when FRACTALIS_MODE contains unknown key
-    """
-    if mode is None:
-        mode = os.getenv('FRACTALIS_MODE', default='production')
 
-    try:
-        app.config.from_object(config[mode])
-    except KeyError as e:
-        raise KeyError("'{}' is no valid value for the FRACTALIS_MODE "
-                       "environment variable.".format(mode)) from e
+# DO NOT MODIFY THIS FILE!
+DEBUG = False
+TESTING = False
+REDIS_HOSTNAME = '127.0.0.1'
+REDIS_PORT = '6379'
+CELERY_BROKER_URL = 'amqp://'
+CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379'
+# DO NOT MODIFY THIS FILE!
diff --git a/fractalis/session.py b/fractalis/session.py
index 85e100c..25a8fe8 100644
--- a/fractalis/session.py
+++ b/fractalis/session.py
@@ -1,10 +1,14 @@
+import math
+import datetime
 from uuid import uuid4
 
-from redislite import StrictRedis
+from redis import StrictRedis
 from flask.sessions import SecureCookieSessionInterface, SecureCookieSession
 
 
 class RedisSession(SecureCookieSession):
+    """An implementation of SecureCookieSession that expands the class with
+    a sid field."""
 
     def __init__(self, sid, initial=None):
         super().__init__(initial=initial)
@@ -12,9 +16,17 @@ class RedisSession(SecureCookieSession):
 
 
 class RedisSessionInterface(SecureCookieSessionInterface):
+    """An implementation of SecureCookieSessionInterface that makes use of
+    Redis as a session storage.
 
-    def __init__(self, redis_db_path):
-        self.redis = StrictRedis(redis_db_path)
+    Fields:
+    redis (StrictRedis) -- The connection to the Redis database
+    sid (UUID) -- A session id
+    """
+
+    def __init__(self, app_config):
+        self.redis = StrictRedis(host=app_config['REDIS_HOSTNAME'],
+                                 port=app_config['REDIS_PORT'])
 
     def open_session(self, app, request):
         sid = request.cookies.get(app.session_cookie_name)
@@ -34,10 +46,38 @@ class RedisSessionInterface(SecureCookieSessionInterface):
             if session.modified:
                 response.delete_cookie(app.session_cookie_name, domain=domain)
             return None
-        session_expiration_time = self.get_expiration_time(app, session)
+        expiration_times = self.get_expiration_times(app, session)
         serialzed_session_data = self.serializer.dumps(dict(session))
-        self.redis.setex('session:{}'.format(session.sid),
-                         session_expiration_time, serialzed_session_data)
-        response.set_cookie(app.session_cookie_name, session.sid,
-                            expires=session_expiration_time, httponly=True,
+        self.redis.setex(name='session:{}'.format(session.sid),
+                         time=expiration_times['redis'],
+                         value=serialzed_session_data)
+        response.set_cookie(key=app.session_cookie_name, value=session.sid,
+                            expires=expiration_times['cookies'], httponly=True,
                             domain=domain)
+
+    def get_expiration_times(self, app, session):
+        """Get dictionary that contains redis session and cookie expiration
+        times in the correct format.
+
+        We need this method for two reasons. First, if the expiration time is
+        None we need to set it to a default. Second, there is a bug that
+        prohibits redislite.Redis.setex method to use a datetime object for
+        expiration time, so this method converts it to integer (seconds).
+
+        Keyword Arguments:
+        app (Flask) -- An instance of a Flask application
+        session (SecureCookieSession) -- An instance of a session
+
+        Returns:
+        (dict) -- A dict containing expiration times for redis and cookie
+        """
+        expiration_times = {'redis': 60 * 60 * 24, 'cookies': None}
+        now = datetime.datetime.utcnow()
+        session_expiration_time = self.get_expiration_time(app, session)
+        if session_expiration_time is not None:
+            seconds = (session_expiration_time - now).total_seconds()
+            expiration_times['redis'] = math.ceil(seconds)
+        cookie_expiration_time = (now + datetime.timedelta(
+            seconds=expiration_times['redis']))
+        expiration_times['cookies'] = cookie_expiration_time
+        return expiration_times
diff --git a/run.py b/run.py
deleted file mode 100644
index a95bf20..0000000
--- a/run.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from fractalis import app
-
-if __name__ == '__main__':
-    app.run()
diff --git a/setup.py b/setup.py
index 78d3bbd..516c826 100644
--- a/setup.py
+++ b/setup.py
@@ -8,8 +8,8 @@ setup(
     packages=find_packages(),
     install_requires=[
         'Flask',
-        'celery',
-        'redislite'
+        'celery[redis]',
+        'redis'
     ],
     setup_requires=[
         'pytest-runner',
diff --git a/tests/test_analytics.py b/tests/test_analytics.py
index 6674259..d847feb 100644
--- a/tests/test_analytics.py
+++ b/tests/test_analytics.py
@@ -1,78 +1,76 @@
 import uuid
-import json
 
+import flask
 import pytest
 
 
 class TestAnalytics(object):
 
-    @pytest.fixture
-    def flask_app(self):
+    @pytest.fixture(scope='module')
+    def app(self):
         from flask import Flask
-        from fractalis.config import configure_app
         app = Flask('test_app')
-        configure_app(app, mode='testing')
+        app.testing = True
         test_client = app.test_client()
         return test_client
 
-    def test_new_resource_created(self, flask_app):
-        response = flask_app.post('/analytics', data=dict(
+    def test_new_resource_created(self, app):
+        response = app.post('/analytics', data=dict(
             script='test/sample.py',
             arguments={'a': 1, 'b': 1}
         ))
-        response_body = json.loads(response.get_data().decode('utf-8'))
+        response_body = flask.json.loads(response.get_data())
         new_resource_url = '/analytics/{}'.format(response_body['job_id'])
         assert response.status_code == 201
         assert uuid.UUID(response_body['job_id'])
-        assert flask_app.head(new_resource_url).status_code == 200
+        assert app.head(new_resource_url).status_code == 200
 
-    def test_400_if_creating_but_script_does_not_exist(self, flask_app):
-        response = flask_app.post('/analytics', data=dict(
+    def test_400_if_creating_but_script_does_not_exist(self, app):
+        response = app.post('/analytics', data=dict(
             script='test/sapmle.py',
             arguments={'a': 1, 'b': 1}
         ))
-        response_body = json.loads(response.get_data().decode('utf-8'))
+        response_body = flask.json.loads(response.get_data())
         assert response.status_code == 400
         assert response_body['error_msg']
 
-    def test_400_if_creating_but_arguments_are_invalid(self, flask_app):
-        response = flask_app.post('/analytics', data=dict(
+    def test_400_if_creating_but_arguments_are_invalid(self, app):
+        response = app.post('/analytics', data=dict(
             script='test/sample.py',
             arguments={'a': 1, 'c': 1}
         ))
-        response_body = json.loads(response.get_data().decode('utf-8'))
+        response_body = flask.json.loads(response.get_data())
         assert response.status_code == 400
         assert response_body['error_msg']
 
-    def test_403_if_creating_but_not_authenticated(self, flask_app):
-        response = flask_app.post('/analytics', data=dict(
+    def test_403_if_creating_but_not_authenticated(self, app):
+        response = app.post('/analytics', data=dict(
             script='test/sample.py',
             arguments={'a': 1, 'b': 1}
         ))
-        response_body = json.loads(response.get_data().decode('utf-8'))
         assert response.status_code == 403
 
-    def test_resource_deleted(self, flask_app):
-        response = flask_app.post('/analytics')
-        response_body = json.loads(response.get_data().decode('utf-8'))
+    def test_resource_deleted(self, app):
+        response = app.post('/analytics')
+        response_body = flask.json.loads(response.get_data())
         new_resource_url = '/analytics/{}'.format(response_body['job_id'])
-        assert flask_app.delete(new_resource_url).status_code == 200
-        assert flask_app.head(new_resource_url).status_code == 404
+        assert app.delete(new_resource_url).status_code == 200
+        assert app.head(new_resource_url).status_code == 404
 
-    def test_403_if_deleting_but_not_authenticated(self, flask_app):
+    def test_403_if_deleting_but_not_authenticated(self, app):
         assert False
 
-    def test_404_if_deleting_non_existing_resource(self, flask_app):
+    def test_404_if_deleting_non_existing_resource(self, app):
         assert False
 
-    def test_403_when_getting_status_but_not_authenticated(self, flask_app):
+    def test_403_when_getting_status_but_not_authenticated(self, app):
         assert False
 
-    def test_status_result_non_empty_if_finished(self, flask_app):
+    def test_status_result_non_empty_if_finished(self, app):
         assert False
 
-    def test_status_result_empty_if_not_finished(self, flask_app):
+    def test_status_result_empty_if_not_finished(self, app):
         assert False
 
-    def test_404_if_status_non_existing_resource(self, flask_app):
+    def test_404_if_status_non_existing_resource(self, app):
         assert False
diff --git a/tests/test_celery.py b/tests/test_celery.py
index 43ac6de..bf46b5a 100644
--- a/tests/test_celery.py
+++ b/tests/test_celery.py
@@ -6,21 +6,20 @@ from fractalis.celery import init_celery
 
 class TestCelery(object):
 
-    @pytest.fixture
+    @pytest.fixture()
     def app(self):
         from flask import Flask
-        from fractalis.config import configure_app
         app = Flask('test_app')
-        configure_app(app, mode='testing')
+        app.config.from_object('fractalis.config')
         return app
 
     def test_exception_if_no_connection_to_broker(self, app):
-        app.config['CELERY_BROKER_URL'] = 'redis+socket:///foobar.socket'
-        with pytest.raises(ConnectionError):
+        app.config['CELERY_BROKER_URL'] = 'redis://lacolhost:6379'
+        with pytest.raises(ConnectionRefusedError):
             init_celery(app)
 
     def test_exception_if_no_connection_to_result_backend(self, app):
-        app.config['CELERY_RESULT_BACKEND'] = 'redis+socket:///foobar.socket'
+        app.config['CELERY_RESULT_BACKEND'] = 'redis://lacolhost:6379'
         with pytest.raises(ConnectionRefusedError):
             init_celery(app)
 
diff --git a/tests/test_config.py b/tests/test_config.py
deleted file mode 100644
index 11160a0..0000000
--- a/tests/test_config.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import os
-from importlib import reload
-
-import pytest
-
-import fractalis
-
-
-class TestConfig(object):
-
-    def test_config_when_test_mode(self):
-        os.environ['FRACTALIS_MODE'] = 'testing'
-        reload(fractalis)
-        assert not fractalis.flask_app.config['DEBUG']
-        assert fractalis.flask_app.config['TESTING']
-
-    def test_config_when_development_mode(self):
-        os.environ['FRACTALIS_MODE'] = 'development'
-        reload(fractalis)
-        assert fractalis.flask_app.config['DEBUG']
-        assert not fractalis.flask_app.config['TESTING']
-
-    def test_config_when_production_mode(self):
-        os.environ['FRACTALIS_MODE'] = 'production'
-        reload(fractalis)
-        assert not fractalis.flask_app.config['DEBUG']
-        assert not fractalis.flask_app.config['TESTING']
-
-    def test_config_when_default(self):
-        del os.environ['FRACTALIS_MODE']
-        reload(fractalis)
-        assert not fractalis.flask_app.config['DEBUG']
-        assert not fractalis.flask_app.config['TESTING']
-
-    def test_config_when_unknown_mode(self):
-        os.environ['FRACTALIS_MODE'] = 'foobar'
-        with pytest.raises(KeyError):
-            reload(fractalis)
diff --git a/tests/test_job.py b/tests/test_job.py
index 67b7f64..e22f69d 100644
--- a/tests/test_job.py
+++ b/tests/test_job.py
@@ -10,40 +10,47 @@ class TestJob(object):
 
     def test_exception_when_starting_non_existing_script(self):
         with pytest.raises(ImportError):
-            job.create_job('querty', {})
+            job.start_job('querty.sample.add', {})
 
     def test_exception_when_invalid_parameters(self):
         with pytest.raises(TypeError):
-            job.create_job('test/sample/add', {'a': 1})
+            job.start_job('test.sample.add', {'a': 1})
 
     def test_start_job_returns_uuid(self):
-        job_id = job.create_job('test/sample/add', {})
+        job_id = job.start_job('test.sample.add', {'a': 1, 'b': 2})
         UUID(job_id)
 
-    def test_job_in_progress_has_running_status(self):
-        job_id = job.create_job('test/sample/do_nothing', {'time': 2})
-        job_details = job.get_job_details(job_id)
-        assert job_details.status == 'RUNNING'
-
     def test_finished_job_returns_results(self):
-        job_id = job.create_job('test/sample/add', {'a': 1, 'b': 2})
+        job_id = job.start_job('test.sample.add', {'a': 1, 'b': 2})
+        sleep(1)
+        async_result = job.get_job_result('test.sample.add', job_id)
+        assert async_result.status == 'SUCCESS'
+        assert async_result.result == 3
+
+    def test_failing_job_return_exception_message(self):
+        job_id = job.start_job('test.sample.div', {'a': 1, 'b': 0})
         sleep(1)
-        job_details = job.get_job_details(job_id)
-        assert job_details.status == 'FINISHED'
-        assert job_details.message == 3
+        async_result = job.get_job_result('test.sample.div', job_id)
+        assert async_result.status == 'FAILURE'
+        assert async_result.result == 'wdawd'
+
+    def test_job_in_progress_has_running_status(self):
+        job_id = job.start_job('test.sample.do_nothing', {'time': 2})
+        async_result = job.get_job_result('test.sample.do_nothing', job_id)
+        assert async_result.status == 'PENDING'
 
     def test_exception_when_checking_non_existing_job(self):
         with pytest.raises(LookupError):
-            job.get_job_details(uuid4())
+            job.get_job_result('test.sample.do_nothing', str(uuid4()))
 
     def test_job_is_gone_after_canceling(self):
-        job_id = job.create_job('test/sample/do_nothing', {'time': 10})
-        job.cancel_job(job_id)
+        job_id = job.start_job('test.sample.do_nothing', {'time': 10})
+        job.cancel_job('test.sample.do_nothing', job_id)
         # TODO Not sure which exception is thrown
         with pytest.raises():
-            job.get_job_details(job_id)
+            job.get_job_result(job_id)
 
     def test_exception_when_canceling_non_existing_job(self):
         # TODO Not sure which exception is thrown
         with pytest.raises():
-            job.cancel_job(uuid4())
+            job.cancel_job('test.sample.do_nothing', uuid4())
diff --git a/tests/test_session.py b/tests/test_session.py
index d2bd46a..e0e0f54 100644
--- a/tests/test_session.py
+++ b/tests/test_session.py
@@ -1,73 +1,85 @@
+from uuid import UUID
 from time import sleep
 
 import pytest
 import flask
-from redislite import StrictRedis
+from redis import StrictRedis
 
 
 class TestSession(object):
 
-    @pytest.fixture
-    def flask_app(self):
+    @pytest.fixture(scope='module')
+    def app(self):
         from flask import Flask
-        from fractalis import configure_app
         from fractalis.session import RedisSessionInterface
         app = Flask('test_app')
-        configure_app(app, mode='testing')
-        app.session_interface = RedisSessionInterface(
-            redis_db_path=app.config['REDIS_DB_PATH'])
+        app.config.from_object('fractalis.config')
+        app.testing = True
+        app.session_interface = RedisSessionInterface(app.config)
         return app
 
-    def test_add_data_to_session_and_expect_it_in_db(self, flask_app):
-        redis = StrictRedis(flask_app.config['REDIS_DB_PATH'])
-        with flask_app.test_client() as test_client:
-            with test_client.session_transaction() as session:
-                session['foo'] = 'bar'
-            session_id = flask.session.sid
-            assert redis.get('session:{}'.format(session_id))['foo'] == 'bar'
+    @pytest.fixture(scope='module')
+    def redis(self, app):
+        redis = StrictRedis(host=app.config['REDIS_HOSTNAME'],
+                            port=app.config['REDIS_PORT'])
+        return redis
 
-    def test_add_data_and_expect_cookie_set(self, flask_app):
-        with flask_app.test_client() as test_client:
-            with test_client.session_transaction() as session:
-                session['foo'] = 'bar'
-            test_client.get()
+    def test_add_data_to_session_and_expect_it_in_db(self, app, redis):
+        with app.test_client() as c:
+            with c.session_transaction() as sess:
+                sess.permanent = True
+                sess['foo'] = 'bar'
+                session_id = sess.sid
+        value = redis.get('session:{}'.format(session_id))
+        assert flask.json.loads(value)['foo'] == 'bar'
+
+    def test_add_data_to_session_and_expect_sid_to_be_uuid(self, app):
+        with app.test_client() as c:
+            with c.session_transaction() as sess:
+                sess.permanent = True
+                sess['foo'] = 'bar'
+                assert sess.sid
+                UUID(sess.sid)
+
+    def test_add_data_and_expect_cookie_set(self, app):
+        with app.test_client() as c:
+            with c.session_transaction() as sess:
+                sess.permanent = True
+                sess['foo'] = 'bar'
+            c.get()
             assert flask.request.cookies
 
-    def test_dont_add_data_and_exoect_no_cookie_set(self, flask_app):
-        with flask_app.test_client() as test_client:
-            test_client.get()
+    def test_dont_add_data_and_exoect_no_cookie_set(self, app):
+        with app.test_client() as c:
+            c.get()
             assert not flask.request.cookies
 
-    def test_change_session_data_and_expect_change_in_db(self, flask_app):
-        redis = StrictRedis(flask_app.config['REDIS_DB_PATH'])
-        with flask_app.test_client() as test_client:
-            with test_client.session_transaction() as session:
-                session['foo'] = 'bar'
-            session_id = flask.session.sid
-            assert redis.get('session:{}'.format(session_id))['foo'] == 'bar'
-            with test_client.session_transaction() as session:
-                session['foo'] = 'baz'
-            assert redis.get('session:{}'.format(session_id))['foo'] == 'baz'
+    def test_change_session_data_and_expect_change_in_db(self, app, redis):
+        with app.test_client() as c:
+            with c.session_transaction() as sess:
+                sess.permanent = True
+                sess['foo'] = 'bar'
+            session_id = sess.sid
+        value = redis.get('session:{}'.format(session_id))
+        assert flask.json.loads(value)['foo'] == 'bar'
+        with app.test_client() as c:
+            with c.session_transaction() as sess:
+                sess.permanent = True
+                sess['foo'] = 'baz'
+            session_id = sess.sid
+        value = redis.get('session:{}'.format(session_id))
+        assert flask.json.loads(value)['foo'] == 'baz'
+
+    def test_session_data_not_in_db_when_expired(self, app, redis):
+        app.config['PERMANENT_SESSION_LIFETIME'] = 1
+        with app.test_client() as c:
+            with c.session_transaction() as sess:
+                sess.permanent = True
+                sess['foo'] = 'bar'
+                session_id = sess.sid
+        sleep(2)
+        assert not redis.get('session:{}'.format(session_id))
 
-    def test_exception_when_manipulating_session_data(self, flask_app):
+    def test_exception_when_manipulating_session_data(self, app):
         # No need to test this atm because we store nothing in the cookie
         assert True
-
-    def test_exception_when_accessing_expired_session_data(self, flask_app):
-        flask_app.config['PERMANENT_SESSION_LIFETIME'] = 1
-        with flask_app.test_client() as test_client:
-            with test_client.session_transaction() as session:
-                session['foo'] = 'bar'
-            sleep(2)
-            #TODO Not sure which exception is thrown
-            flask.session['foo']
-
-    def test_session_data_not_in_db_when_expired(self, flask_app):
-        flask_app.config['PERMANENT_SESSION_LIFETIME'] = 1
-        redis = StrictRedis(flask_app.config['REDIS_DB_PATH'])
-        with flask_app.test_client() as test_client:
-            with test_client.session_transaction() as session:
-                session['foo'] = 'bar'
-            sleep(2)
-            session_id = flask.session.sid
-            assert not redis.get('session:{}'.format(session_id))['foo']
-- 
GitLab