Progress with tests

This commit is contained in:
Jan-Jelle Kester 2014-03-14 17:15:31 +01:00
parent 6c3ec169ee
commit 41d3948606
3 changed files with 79 additions and 8 deletions

View file

@ -20,19 +20,16 @@ class AuditlogMiddleware(object):
"""
if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated') and request.user.is_authenticated():
user = request.user
else:
user = None
request.auditlog_ts = time.time()
set_actor = curry(self.set_actor, user)
pre_save.connect(set_actor, sender=LogEntry, dispatch_uid=(self.__class__, request.auditlog_ts), weak=False)
request.auditlog_ts = time.time()
set_actor = curry(self.set_actor, user)
pre_save.connect(set_actor, sender=LogEntry, dispatch_uid=(self.__class__, request.auditlog_ts), weak=False)
def process_response(self, request, response):
"""
Disconnects the signal receiver to prevent it from staying active.
"""
# Disconnecting the signal receiver is required because it will not be garbage collected (non-weak reference)
if hasattr(request, 'auditlog_ts'): # admin wipes auditlog_ts from request...
if hasattr(request, 'auditlog_ts'):
pre_save.disconnect(sender=LogEntry, dispatch_uid=(self.__class__, request.auditlog_ts))
return response

View file

@ -78,6 +78,11 @@ class LogEntry(models.Model):
"""
class Action:
"""
The actions that Auditlog distinguishes: creating, updating and deleting objects. Viewing objects is not logged.
The values of the actions are numeric, a higher integer value means a more intrusive action. This may be useful
in some cases when comparing actions because __lt, __lte, __gt, __gte can be used in queries.
"""
CREATE = 0
UPDATE = 1
DELETE = 2
@ -157,6 +162,9 @@ class AuditlogHistoryField(generic.GenericRelation):
By default this field will assume that your primary keys are numeric, simply because this is the most common case.
However, if you have a non-integer primary key, you can simply pass pk_indexable=False to the constructor, and
Auditlog will fall back to using a non-indexed text based field for this model.
Using this field will not automatically register the model for automatic logging. This is done so you can be more
flexible with how you use this field.
"""
def __init__(self, pk_indexable=True, **kwargs):

View file

@ -1,5 +1,10 @@
import datetime
from django.test import TestCase
from django.contrib.auth.models import User, AnonymousUser
from django.core.exceptions import ValidationError
from django.db.models.signals import pre_save
from django.http import HttpResponse
from django.test import TestCase, RequestFactory
from auditlog.middleware import AuditlogMiddleware
from auditlog.models import LogEntry
from testapp.models import SimpleModel, AltPrimaryKeyModel, ProxyModel
@ -67,3 +72,64 @@ class AltPrimaryKeyModelTest(SimpleModelTest):
class ProxyModelTest(SimpleModelTest):
def setUp(self):
self.obj = ProxyModel.objects.create(text='I am not what you think.')
class MiddlewareTest(TestCase):
"""
Test the middleware responsible for connecting and disconnecting the signals used in automatic logging.
"""
def setUp(self):
self.middleware = AuditlogMiddleware()
self.factory = RequestFactory()
self.user = User.objects.create_user(username='test', email='test@example.com', password='top_secret')
def test_request_anonymous(self): # TODO does not seem to validate
"""No actor will be logged when a user is not logged in."""
# Create a request
request = self.factory.get('/')
request.user = AnonymousUser()
# Run middleware
self.middleware.process_request(request)
# Validate result
self.assertFalse(pre_save.has_listeners(LogEntry))
def test_request(self):
"""The actor will be logged when a user is logged in."""
# Create a request
request = self.factory.get('/')
request.user = self.user
# Run middleware
self.middleware.process_request(request)
# Validate result
self.assertTrue(pre_save.has_listeners(LogEntry))
def test_response(self): # TODO does not seem to validate
"""The signal will be disconnected when the request is processed."""
# Create a request
request = self.factory.get('/')
request.user = self.user
# Run middleware
self.middleware.process_request(request)
self.assertTrue(pre_save.has_listeners(LogEntry)) # The signal should be present before trying to disconnect it.
self.middleware.process_response(request, HttpResponse())
# Validate result
self.assertFalse(pre_save.has_listeners(LogEntry))
def test_exception(self):
"""The signal will be disconnected when an exception is raised."""
# Create a request
request = self.factory.get('/')
request.user = self.user
# Run middleware
self.middleware.process_request(request)
self.assertTrue(pre_save.has_listeners(LogEntry)) # The signal should be present before trying to disconnect it.
self.middleware.process_exception(request, ValidationError("Test"))
# Validate result
self.assertFalse(pre_save.has_listeners(LogEntry))