Files @ b95586a70595
Branch filter:

Location: conntrackt/conntrackt/tests/helpers.py - annotation

branko
CONNT-11: Converted tests to directly use the views, and implemented mocking of some classes where necessary (like the messages framework). Removed all integration tests for now.
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
b95586a70595
# Python standard library imports.
from types import FunctionType

# Python third-party library imports.
import mock

# Django imports.
from django.core.exceptions import PermissionDenied
from django.contrib.auth.models import User, Permission
from django.test import RequestFactory


def create_get_request(url="/fake-path/", user=None):
    """
    Helper function for generating a GET request that can be passed on to a
    view.

    Arguments:

        url - URL that should be used for the request. Default is "/fake-path/".

        user - Django user to be passed on into the request. Default is
        mock.Mock().
    """

    request = RequestFactory().get(url)

    # If user was not provided, construct one using mocking.
    if user is None:
        user = mock.Mock()

    request.user = user

    return request


def generate_get_response(view, request=None, *args, **kwargs):
    """
    Generates a get response, passing the request, positional and keyword
    arguments to it as well.

    Attributes:

        view - View function that should be called.

        request - Request object to pass into view. Default is to create a new
        request using the create_get_request() call.

        *args - Additional positional arguments that will be passed into view.

        *kwargs - Additional keyword arguments that will be passed into view.
    """

    # If no request was provided, construct it.
    if request is None:
        request = create_get_request()

    return view(request, *args, **kwargs)


class PermissionTestMixin(object):
    """
    Mixin class for testing if permission requirement is applied properly for
    accessing a view.

    In order to use this mixin, add it the left side of the class list the test
    is inheriting from, and configure it providing the following class options:

        view_class - Class used for the CBV that will be tested.
        view_function - View function that will be tested.
        sufficient_permissions - Permissions sufficient to gain access to view.
        permission_test_view_args - Positional arguments to pass to the view.
        permission_test_view_kwargs - Keyword arguments to pass to the view.
    """

    view_class = None
    view_function = None
    permission_test_view_args = ()
    permission_test_view_kwargs = {}
    sufficient_permissions = ()

    def __init__(self, *args, **kwargs):
        """
        Initialises the mixin. Takes care of some basic validation of passed
        configuration options.
        """

        super(PermissionTestMixin, self).__init__(*args, **kwargs)

        if self.view_class is None and self.view_function is None:
            raise ValueError("Permission test mixin configured improperly - no CBV class or function was supplied via parameters 'view_class' or 'view_function'.")

        if self.view_function is not None and type(self.view_function) is not FunctionType:
            raise ValueError("Permission test mixin configured improperly - provided 'view_function' is not function. Did you forget to wrap the function with staticmethod() perhaps?")

        if type(self.permission_test_view_kwargs) is not dict:
            raise ValueError("Permission text mixin configured improperly - parameter 'permission_test_view_kwargs' must be a dictionary.")

        if type(self.permission_test_view_args) is not tuple:
            raise ValueError("Permission text mixin configured improperly - parameter 'permission_test_view_args' must be a tuple.")

        if type(self.sufficient_permissions) is not tuple:
            raise ValueError("Permission text mixin configured improperly - parameter 'sufficient_permissions' must be a tuple.")

    def test_permission_granted(self):
        # Set-up a request from user with sufficient privileges.
        request = RequestFactory().get("/fake-path")
        user = User.objects.create(username="user", password="password")
        for permission in self.sufficient_permissions:
            user.user_permissions.add(Permission.objects.get(codename=permission))
        request.user = user

        # Get the view.
        if self.view_class is not None:
            view = self.view_class.as_view()
        elif self.view_function is not None:
            view = self.view_function

        # Verify that permission is granted
        args = self.permission_test_view_args
        kwargs = self.permission_test_view_kwargs

        try:
            response = view(request, *args, **kwargs)
        except PermissionDenied:
            self.fail("Failed to access view with user privileges: %s" % str(self.sufficient_permissions))

        self.assertEqual(response.status_code, 200)

    def test_permission_denied(self):
        # Set-up a request from user with insufficient privileges.
        request = RequestFactory().get("/fake-path")
        request.user = User.objects.create(username="user", password="password")

        # Get the view.
        if self.view_class:
            view = self.view_class.as_view()
        elif self.view_function:
            view = self.view_function
        
        # Verify that permission is denied.
        args = self.permission_test_view_args
        kwargs = self.permission_test_view_kwargs
        self.assertRaises(PermissionDenied, view, request, *args, **kwargs)


class FakeMessages(object):
    """
    Helper class for mocking the Django messages framework.
    """

    def __init__(self):
        """
        Initalises the message framework mocker.

        Set-ups the messages list prpoperty.
        """
        self.messages = []

    def add(self, level, message, extra_tags):
        """
        Adds a message.
        """

        self.messages.append(message)