This repository has been archived by the owner on Jan 23, 2024. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* WIP Debugging issue with django-easy-audit * WIP narrowing down easyaudit bug * WIP Continued work on easyaudit problem * Finished adding easyaudit and related integration tests * adjust expected queries for easyaudit * remove crudevents and loginevents from the django admin site * check number of groups in curdevents, not group ids * Reduce num of queries in test based on performance-enchanced fork of easyaudit
- Loading branch information
Showing
17 changed files
with
248 additions
and
42 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from easyaudit.models import CRUDEvent, LoginEvent | ||
from django.contrib import admin | ||
|
||
|
||
admin.site.unregister(CRUDEvent) | ||
admin.site.unregister(LoginEvent) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
|
||
def dont_audit_fixture_loading( | ||
instance, object_json_repr, created, raw, using, update_fields, | ||
**kwargs): | ||
return not raw |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from intake.middleware import MiddlewareBase | ||
from easyaudit.middleware.easyaudit import clear_request | ||
|
||
|
||
class ClearRequestMiddleware(MiddlewareBase): | ||
|
||
def process_response(self, response): | ||
clear_request() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from django.test import TestCase | ||
from user_accounts.tests.factories import UserProfileFactory | ||
from django.conf import settings | ||
from easyaudit.middleware.easyaudit import ( | ||
get_current_request, get_current_user) | ||
|
||
|
||
class TestMiddleware(TestCase): | ||
""" | ||
easyaudit does not properly clear requests after they're finished | ||
This means that users can be misattributed to subsequent actions. | ||
Our middleware forces the request to be cleared. | ||
""" | ||
|
||
def test_request_is_cleared(self): | ||
# log in user | ||
user = UserProfileFactory().user | ||
self.client.login( | ||
username=user.username, password=settings.TEST_USER_PASSWORD) | ||
|
||
# do action | ||
self.client.get('/') | ||
# check if request is cleared | ||
self.assertIsNone(get_current_request()) | ||
self.assertIsNone(get_current_user()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
Feature: CRUD events are audited | ||
Background: | ||
Given a superuser | ||
And an org user at "ebclc" | ||
|
||
Scenario: Admin actions create CRUD events | ||
Given I log in as a superuser | ||
When I go to the admin edit page for "ebclc" user | ||
And I check "is_staff" | ||
And I select the "followup_staff" option in "groups_old" | ||
And I click "a#id_groups_add_link" | ||
And I click "input[name='_save']" | ||
Then the latest "auth.User" "update" event should have "superuser" as the user | ||
And the latest "auth.User" "update" event should have "True" for "is_staff" | ||
And the latest "auth.User" "m2m_change" event should have "2" ids in "groups" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import json | ||
from behave import when, then | ||
from easyaudit.models import CRUDEvent | ||
from django.contrib.auth.models import User | ||
from django.contrib.contenttypes.models import ContentType | ||
from django.core.urlresolvers import reverse | ||
from pprint import pprint | ||
from urllib.parse import urljoin | ||
|
||
|
||
def get_latest_crudevent_for_appmodel_and_event_type(content_type, event_type): | ||
# acceptable values are: | ||
# "create", "update", "delete", "m2m_change", "m2m_change_rev" | ||
event_type_idx = getattr(CRUDEvent, event_type.upper()) | ||
content_type_app, content_type_model = content_type.lower().split(".") | ||
event_model_content_type_id = ContentType.objects.filter( | ||
app_label=content_type_app, | ||
model=content_type_model).first().id | ||
return CRUDEvent.objects.filter( | ||
event_type=event_type_idx, | ||
content_type_id=event_model_content_type_id).latest('datetime') | ||
|
||
|
||
@when('I go to the admin edit page for "{org_slug}" user') | ||
def visit_org_user_admin_edit_page(context, org_slug): | ||
user = User.objects.filter(profile__organization__slug=org_slug).first() | ||
url = reverse('admin:auth_user_change', args=[user.id]) | ||
context.browser.get(urljoin(context.test.live_server_url, url)) | ||
|
||
|
||
@then('the latest CRUD event should not have a user') | ||
def test_latest_crud_event_no_user(context): | ||
badevent = CRUDEvent.objects.latest('datetime') | ||
print(vars(badevent)) | ||
context.test.assertIsNone(badevent.user) | ||
|
||
|
||
@then(str( | ||
'the latest "{content_type}" "{event_type}" event should have "{username}"' | ||
' as the user')) | ||
def test_crudevent_username(context, content_type, event_type, username): | ||
expected_event = get_latest_crudevent_for_appmodel_and_event_type( | ||
content_type, event_type) | ||
context.test.assertEqual(username, expected_event.user.username) | ||
|
||
|
||
@then(str( | ||
'the latest "{content_type}" "{event_type}" event should have "{value}"' | ||
' for "{key}"')) | ||
def test_crudevent_has_matching_property( | ||
context, content_type, event_type, value, key): | ||
expected_event = get_latest_crudevent_for_appmodel_and_event_type( | ||
content_type, event_type) | ||
event_data = json.loads(expected_event.object_json_repr)[0] | ||
context.test.assertEqual(value, str(event_data["fields"][key])) | ||
|
||
|
||
@then(str( | ||
'the latest "{content_type}" "{event_type}" event should have ' | ||
'"{id_count}" ids in "{field_name}"')) | ||
def test_crudevent_property_contains( | ||
context, content_type, event_type, id_count, field_name): | ||
expected_event = get_latest_crudevent_for_appmodel_and_event_type( | ||
content_type, event_type) | ||
event_data = json.loads(expected_event.object_json_repr)[0] | ||
context.test.assertEqual( | ||
int(id_count), len(event_data["fields"][field_name])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import factory | ||
from intake import models | ||
from user_accounts.tests.factories import UserFactory | ||
from .tag_factory import TagFactory | ||
from .form_submission_factory import FormSubmissionFactory | ||
|
||
|
||
class SubmissionTagLinkFactory(factory.DjangoModelFactory): | ||
content_object = factory.SubFactory(FormSubmissionFactory) | ||
tag = factory.SubFactory(TagFactory) | ||
user = factory.SubFactory(UserFactory) | ||
|
||
class Meta: | ||
model = models.SubmissionTagLink |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import factory | ||
from taggit import models | ||
|
||
|
||
class TagFactory(factory.DjangoModelFactory): | ||
name = factory.Sequence(lambda n: 'tag-{}'.format(n)) | ||
|
||
class Meta: | ||
model = models.Tag |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,49 @@ | ||
from django.test import TestCase | ||
from intake.tests import mock | ||
from user_accounts.tests.mock import create_user | ||
from intake.tests.factories import SubmissionTagLinkFactory | ||
from intake import models | ||
from taggit.models import Tag | ||
from django.contrib.auth.models import User | ||
from intake import models | ||
|
||
|
||
class TestSubmissionTagLink(TestCase): | ||
|
||
def setUp(self): | ||
super().setUp() | ||
self.sub = mock.make_submission() | ||
self.sub_id = self.sub.id | ||
self.user = create_user() | ||
self.user_id = self.user.id | ||
self.tag = mock.make_tag() | ||
self.tag_id = self.tag.id | ||
|
||
def make_link(self): | ||
link = models.SubmissionTagLink( | ||
content_object_id=self.sub_id, user_id=self.user_id, | ||
tag_id=self.tag_id) | ||
link.save() | ||
return link | ||
|
||
def test_creation(self): | ||
link = self.make_link() | ||
link = SubmissionTagLinkFactory() | ||
self.assertTrue(link.added) | ||
|
||
def test_related_queries(self): | ||
link = self.make_link() | ||
results = self.sub.tags.all() | ||
self.assertIn(self.tag, results) | ||
self.assertIn(link, self.tag.intake_submissiontaglink_items.all()) | ||
self.assertIn(link, self.sub.tag_links.all()) | ||
link = SubmissionTagLinkFactory() | ||
results = link.content_object.tags.all() | ||
self.assertIn(link.tag, results) | ||
self.assertIn(link, link.tag.intake_submissiontaglink_items.all()) | ||
self.assertIn(link, link.content_object.tag_links.all()) | ||
results = models.FormSubmission.objects.filter( | ||
tags__name=self.tag.name) | ||
self.assertIn(self.sub, results) | ||
tags__name=link.tag.name) | ||
self.assertIn(link.content_object, results) | ||
|
||
def test_deletion(self): | ||
link = self.make_link() | ||
link = SubmissionTagLinkFactory() | ||
# make sure related objects still exist after deletion | ||
link.delete() | ||
self.assertEqual( | ||
models.FormSubmission.objects.filter(id=self.sub_id).count(), 1) | ||
models.FormSubmission.objects.filter( | ||
id=link.content_object_id).count(), 1) | ||
self.assertEqual( | ||
Tag.objects.filter(id=self.tag_id).count(), 1) | ||
Tag.objects.filter(id=link.tag_id).count(), 1) | ||
self.assertEqual( | ||
User.objects.filter(id=self.user_id).count(), 1) | ||
self.assertEqual(self.sub.tags.all().count(), 0) | ||
User.objects.filter(id=link.user_id).count(), 1) | ||
self.assertEqual(link.content_object.tags.all().count(), 0) | ||
|
||
def test_tag_deletion(self): | ||
# Deletes link if tag is deleted | ||
link_id = self.make_link().id | ||
Tag.objects.filter(id=self.tag_id).delete() | ||
link = SubmissionTagLinkFactory() | ||
Tag.objects.filter(id=link.tag_id).delete() | ||
self.assertEqual( | ||
models.SubmissionTagLink.objects.filter(id=link_id).count(), 0) | ||
models.SubmissionTagLink.objects.filter(id=link.id).count(), 0) | ||
|
||
def test_user_deletion(self): | ||
# Link remains if user is deleted, with link.user = None | ||
link_id = self.make_link().id | ||
User.objects.filter(id=self.user_id).delete() | ||
link = models.SubmissionTagLink.objects.get(id=link_id) | ||
link = SubmissionTagLinkFactory() | ||
User.objects.filter(id=link.user_id).delete() | ||
link = models.SubmissionTagLink.objects.get(id=link.id) | ||
self.assertEqual(link.user, None) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters