diff --git a/tracker/fixtures/test_tracker_views.json b/tracker/fixtures/test_tracker_views.json index d4dee97..b92cdce 100644 --- a/tracker/fixtures/test_tracker_views.json +++ b/tracker/fixtures/test_tracker_views.json @@ -1,4 +1,66 @@ [ + { + "fields": { + "date_joined": "2014-09-03T06:34:06.019Z", + "email": "", + "first_name": "", + "groups": [], + "is_active": true, + "is_staff": true, + "is_superuser": true, + "last_login": "2014-09-03T06:34:26.544Z", + "last_name": "", + "password": "pbkdf2_sha256$12000$WrD5Mo69v7O1$JqUWSog9wxF7wyJz+esO9EHlv9j+boD58VODEq+jYLY=", + "user_permissions": [], + "username": "admin" + }, + "model": "accounts.user", + "pk": 1 + }, + { + "fields": { + "date_joined": "2014-09-03T06:34:39.486Z", + "email": "", + "first_name": "", + "groups": [], + "is_active": true, + "is_staff": false, + "is_superuser": false, + "last_login": "2014-09-03T06:34:39.486Z", + "last_name": "", + "password": "pbkdf2_sha256$12000$51A5s5i71FWd$yOFaM/fJGEdykCbfhDRWbz0z/KGHiUNbM3mPzrieDe4=", + "user_permissions": [], + "username": "user1" + }, + "model": "accounts.user", + "pk": 2 + }, + { + "fields": { + "access": 1, + "description": "", + "display_name": "Project 1", + "name": "project-1", + "subscribers": [ + 1 + ] + }, + "model": "tracker.project", + "pk": 1 + }, + { + "fields": { + "access": 1, + "description": "", + "display_name": "Project 2", + "name": "project-2", + "subscribers": [ + 1 + ] + }, + "model": "tracker.project", + "pk": 2 + }, { "fields": { "color": "#FF0000", @@ -77,52 +139,14 @@ }, { "fields": { - "date_joined": "2014-09-03T06:34:06.019Z", - "email": "", - "first_name": "", - "groups": [], - "is_active": true, - "is_staff": true, - "is_superuser": true, - "last_login": "2014-09-03T06:34:26.544Z", - "last_name": "", - "password": "pbkdf2_sha256$12000$WrD5Mo69v7O1$JqUWSog9wxF7wyJz+esO9EHlv9j+boD58VODEq+jYLY=", - "user_permissions": [], - "username": "admin" + "closed": false, + "due_date": null, + "name": "v2.0", + "project": 1 }, - "model": "accounts.user", - "pk": 1 - }, - { - "fields": { - "date_joined": "2014-09-03T06:34:39.486Z", - "email": "", - "first_name": "", - "groups": [], - "is_active": true, - "is_staff": false, - "is_superuser": false, - "last_login": "2014-09-03T06:34:39.486Z", - "last_name": "", - "password": "pbkdf2_sha256$12000$51A5s5i71FWd$yOFaM/fJGEdykCbfhDRWbz0z/KGHiUNbM3mPzrieDe4=", - "user_permissions": [], - "username": "user1" - }, - "model": "accounts.user", + "model": "tracker.milestone", "pk": 2 }, - { - "fields": { - "_args": "{}", - "additionnal_section": "", - "author": 1, - "code": 11, - "date": "2014-09-03T06:34:57.233Z", - "issue": 1 - }, - "model": "tracker.event", - "pk": 1 - }, { "fields": { "assignee": null, @@ -143,28 +167,178 @@ }, { "fields": { - "access": 1, - "description": "", - "display_name": "Project 1", - "name": "project-1", + "assignee": null, + "author": 1, + "closed": false, + "id": 2, + "labels": [ + 1 + ], + "milestone": 2, + "opened_at": "2014-09-03T23:29:39.323Z", + "project": 1, "subscribers": [ 1 - ] + ], + "title": "THE Issue 2" }, - "model": "tracker.project", + "model": "tracker.issue", + "pk": 2 + }, + { + "fields": { + "_args": "{}", + "additionnal_section": "", + "author": 1, + "code": 11, + "date": "2014-09-03T06:34:57.233Z", + "issue": 1 + }, + "model": "tracker.event", "pk": 1 }, { "fields": { - "access": 1, - "description": "", - "display_name": "Project 2", - "name": "project-2", - "subscribers": [ - 1 - ] + "_args": "{}", + "additionnal_section": "", + "author": 1, + "code": 11, + "date": "2014-09-03T23:29:39.681Z", + "issue": 2 }, - "model": "tracker.project", + "model": "tracker.event", "pk": 2 + }, + { + "fields": { + "_args": "{\"label\": 2}", + "additionnal_section": "", + "author": 1, + "code": 4, + "date": "2014-09-03T23:29:47.123Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 3 + }, + { + "fields": { + "_args": "{\"label\": 1}", + "additionnal_section": "", + "author": 1, + "code": 4, + "date": "2014-09-03T23:29:50.770Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 4 + }, + { + "fields": { + "_args": "{\"label\": 2}", + "additionnal_section": "", + "author": 1, + "code": 5, + "date": "2014-09-03T23:29:52.923Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 5 + }, + { + "fields": { + "_args": "{\"milestone\": \"v1.0\"}", + "additionnal_section": "", + "author": 1, + "code": 6, + "date": "2014-09-03T23:30:42.882Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 6 + }, + { + "fields": { + "_args": "{\"new_milestone\": \"v2.0\", \"old_milestone\": \"v1.0\"}", + "additionnal_section": "", + "author": 1, + "code": 7, + "date": "2014-09-03T23:30:50.658Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 7 + }, + { + "fields": { + "_args": "{}", + "additionnal_section": "Fixed.", + "author": 1, + "code": 10, + "date": "2014-09-03T23:31:04.039Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 8 + }, + { + "fields": { + "_args": "{}", + "additionnal_section": "", + "author": 1, + "code": 1, + "date": "2014-09-03T23:31:06.544Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 9 + }, + { + "fields": { + "_args": "{}", + "additionnal_section": "", + "author": 1, + "code": 2, + "date": "2014-09-03T23:31:12.222Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 10 + }, + { + "fields": { + "_args": "{\"old_title\": \"Issue 2\", \"new_title\": \"THE Issue 2\"}", + "additionnal_section": "", + "author": 1, + "code": 3, + "date": "2014-09-03T23:39:33.983Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 11 + }, + { + "fields": { + "_args": "{\"milestone\": \"v2.0\"}", + "additionnal_section": "", + "author": 1, + "code": 8, + "date": "2014-09-03T23:40:51.117Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 12 + }, + { + "fields": { + "_args": "{\"milestone\": \"v1.0\"}", + "additionnal_section": "", + "author": 1, + "code": 6, + "date": "2014-09-03T23:40:54.706Z", + "issue": 2 + }, + "model": "tracker.event", + "pk": 13 } ] diff --git a/tracker/tests.py b/tracker/tests.py index eb760ec..b2bd17d 100644 --- a/tracker/tests.py +++ b/tracker/tests.py @@ -3,6 +3,7 @@ from django.core.urlresolvers import reverse from tracker.models import * from accounts.models import User +from permissions.models import PermissionModel as PermModel class TestViews(TestCase): @@ -15,10 +16,22 @@ class TestViews(TestCase): def test_admin(self): response = self.client.get(reverse('admin')) self.assertRedirects(response, reverse('settings')) + self.client.logout() + response = self.client.get(reverse('admin')) + self.assertRedirects(response, reverse('login')+'?next='+reverse('admin')) + self.client.login(username='user1', password='user1') + response = self.client.get(reverse('admin')) + self.assertEqual(response.status_code, 403) def test_settings(self): response = self.client.get(reverse('settings')) self.assertEqual(response.status_code, 200) + self.client.logout() + response = self.client.get(reverse('settings')) + self.assertRedirects(response, reverse('login')+'?next='+reverse('settings')) + self.client.login(username='user1', password='user1') + response = self.client.get(reverse('settings')) + self.assertEqual(response.status_code, 403) # Projects @@ -28,22 +41,82 @@ class TestViews(TestCase): Project.objects.all().delete() response = self.client.get(reverse('list-project')) self.assertRedirects(response, reverse('add-project')) + self.client.logout() + response = self.client.get(reverse('list-project')) + self.assertEqual(response.status_code, 200) def test_project_add(self): + count = Project.objects.count() response = self.client.get(reverse('add-project')) self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('add-project'), { + 'display_name': 'project 1', # Project 1 already exist + 'name': 'newproject', + 'description': '', + 'access': Project.ACCESS_PUBLIC, + }) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'already a project') + response = self.client.post(reverse('add-project'), { + 'display_name': 'New project', + 'name': 'admin', # reserved name + 'description': '', + 'access': Project.ACCESS_PUBLIC, + }) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'this URL is reserved') + response = self.client.post(reverse('add-project'), { + 'display_name': 'New project', + 'name': 'newproject', + 'description': '', + 'access': Project.ACCESS_PUBLIC, + }) + self.assertEqual(Project.objects.count(), count + 1) + project = Project.objects.get(name='newproject') + self.assertRedirects(response, reverse('list-project-permission', args=[project.name])) + self.assertEqual(project.permissions.count(), 1) + perm = project.permissions.first() + self.assertEqual(perm.grantee_type, PermModel.GRANTEE_USER) + user = User.objects.get(username='admin') + self.assertEqual(perm.grantee_id, user.id) def test_project_edit(self): - project = Project.objects.first() + project = Project.objects.get(name='project-1') response = self.client.get(reverse('edit-project', args=[project.name])) self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('edit-project', args=[project.name]), { + 'display_name': 'project 2', # Project 2 already exist + 'name': 'newproject', + 'description': '', + 'access': Project.ACCESS_PUBLIC, + }) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'already a project') + response = self.client.post(reverse('edit-project', args=[project.name]), { + 'display_name': 'New project name', + 'name': 'admin', # reserved name + 'description': '', + 'access': Project.ACCESS_PUBLIC, + }) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'this URL is reserved') + response = self.client.post(reverse('edit-project', args=[project.name]), { + 'display_name': 'New project name', + 'name': project.name, + 'access': project.access, + }) + self.assertRedirects(response, reverse('list-issue', args=[project.name])) + project = Project.objects.get(pk=project.pk) + self.assertEqual(project.display_name, 'New project name') def test_project_delete(self): + count = Project.objects.count() project = Project.objects.first() response = self.client.get(reverse('delete-project', args=[project.name])) self.assertEqual(response.status_code, 405) # get method not allowed response = self.client.post(reverse('delete-project', args=[project.name])) self.assertRedirects(response, reverse('list-project')) + self.assertEqual(Project.objects.count(), count - 1) def test_project_subscribe_unsubscribe(self): self.client.logout() @@ -51,6 +124,9 @@ class TestViews(TestCase): user = User.objects.get(username='user1') project = Project.objects.get(name='project-1') self.assertFalse(user in project.subscribers.all()) + response = self.client.get(reverse('unsubscribe-project', args=[project.name]), follow=True) + self.assertRedirects(response, reverse('list-issue', args=[project.name])) + self.assertContains(response, 'not subscribed to this project') response = self.client.get(reverse('subscribe-project', args=[project.name])) self.assertRedirects(response, reverse('profile')) user.email = 'user@example.com' @@ -59,10 +135,18 @@ class TestViews(TestCase): self.assertRedirects(response, reverse('list-issue', args=[project.name])) project = Project.objects.get(pk=project.pk) self.assertTrue(user in project.subscribers.all()) + response = self.client.get(reverse('subscribe-project', args=[project.name]), follow=True) + self.assertRedirects(response, reverse('list-issue', args=[project.name])) + self.assertContains(response, 'already subscribed') response = self.client.get(reverse('unsubscribe-project', args=[project.name])) self.assertRedirects(response, reverse('list-issue', args=[project.name])) project = Project.objects.get(pk=project.pk) self.assertFalse(user in project.subscribers.all()) + # test redirect with next= + response = self.client.get(reverse('subscribe-project', args=[project.name])+'?next='+reverse('profile')) + self.assertRedirects(response, reverse('profile')) + response = self.client.get(reverse('unsubscribe-project', args=[project.name])+'?next='+reverse('profile')) + self.assertRedirects(response, reverse('profile')) # Issue @@ -70,32 +154,113 @@ class TestViews(TestCase): project = Project.objects.get(name='project-1') response = self.client.get(reverse('list-issue', args=[project.name])) self.assertEqual(response.status_code, 200) + url = reverse('list-issue', args=['not-existing-project']) + response = self.client.get(url) + self.assertEqual(response.status_code, 403) + self.client.logout() + response = self.client.get(url) + self.assertRedirects(response, reverse('login')+'?next='+url) def test_issue_add(self): + count = Issue.objects.count() project = Project.objects.get(name='project-1') response = self.client.get(reverse('add-issue', args=[project.name])) self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('add-issue', args=[project.name]), { + 'title': 'new issue', + 'description': 'New issue.', + }) + issue = Issue.objects.get(title='new issue') + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + self.assertEqual(Issue.objects.count(), count + 1) + response = self.client.post(reverse('add-issue', args=[project.name]), { + 'title': 'new issue bis', + }) + issue = Issue.objects.get(title='new issue bis') + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + self.assertEqual(Issue.objects.count(), count + 2) def test_issue_edit(self): project = Project.objects.get(name='project-1') issue = project.issues.first() + count = issue.events.count() response = self.client.get(reverse('edit-issue', args=[project.name, issue.id])) self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('edit-issue', args=[project.name, issue.id]), { + 'title': 'new title', + }, follow=True) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + self.assertContains(response, 'updated successfully') + issue = Issue.objects.get(pk=issue.pk) + self.assertEqual(issue.title, 'new title') + self.assertEqual(issue.events.count(), count + 1) + response = self.client.post(reverse('edit-issue', args=[project.name, issue.id]), { + 'title': 'new title', + 'description': 'new description', + }, follow=True) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + self.assertContains(response, 'updated successfully') + issue = Issue.objects.get(pk=issue.pk) + self.assertEqual(issue.description, 'new description') + response = self.client.post(reverse('edit-issue', args=[project.name, issue.id]), { + 'title': 'new title', + 'description': 'new description', + }, follow=True) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + self.assertContains(response, 'not modified') def test_issue_details(self): project = Project.objects.get(name='project-1') issue = project.issues.get(title='Issue 1') response = self.client.get(reverse('show-issue', args=[project.name, issue.id])) self.assertEqual(response.status_code, 200) + issue = project.issues.get(title='THE Issue 2') + response = self.client.get(reverse('show-issue', args=[project.name, issue.id])) + self.assertEqual(response.status_code, 200) def test_issue_comment_add(self): - pass + project = Project.objects.get(name='project-1') + issue = project.issues.get(title='Issue 1') + count = issue.comments.count() + response = self.client.get(reverse('comment-issue', args=[project.name, issue.id])) + self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('comment-issue', args=[project.name, issue.id]), { + 'comment': 'New comment.', + }) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + issue = Issue.objects.get(pk=issue.pk) + self.assertEqual(issue.comments.count(), count + 1) def test_issue_comment_edit(self): - pass + project = Project.objects.get(name='project-1') + issue = project.issues.get(title='THE Issue 2') + comment = issue.comments.first() + response = self.client.get(reverse('edit-comment', args=[project.name, issue.id, comment.id])) + self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('edit-comment', args=[project.name, issue.id, comment.id]), { + 'comment': 'New comment.', + }, follow=True) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + self.assertContains(response, 'modified successfully') + comment = Event.objects.get(pk=comment.pk) + self.assertEqual(comment.additionnal_section, 'New comment.') + response = self.client.post(reverse('edit-comment', args=[project.name, issue.id, comment.id]), { + 'comment': 'New comment.', + }, follow=True) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + self.assertContains(response, 'not modified') def test_issue_comment_delete(self): - pass + project = Project.objects.get(name='project-1') + issue = project.issues.get(title='THE Issue 2') + count = issue.comments.count() + comment = issue.comments.first() + response = self.client.get(reverse('delete-comment', args=[project.name, issue.id, comment.id])) + self.assertEqual(response.status_code, 405) # get method not allowed + response = self.client.post(reverse('delete-comment', args=[project.name, issue.id, comment.id])) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + issue = Issue.objects.get(pk=issue.pk) + self.assertEqual(issue.comments.count(), count - 1) def test_issue_close_reopen(self): issue = Issue.objects.filter(closed=False).first() @@ -123,17 +288,50 @@ class TestViews(TestCase): self.assertRedirects(response, reverse('list-issue', args=[project.name])) self.assertEqual(Issue.objects.count(), count - 1) - def test_issue_add_label(self): - pass + def test_issue_add_remove_label(self): + project = Project.objects.get(name='project-1') + issue = project.issues.get(title='Issue 1') + count = issue.events.count() + label = project.labels.get(name='documentation') + self.assertFalse(label in issue.labels.all()) + response = self.client.get(reverse('add-label-to-issue', args=[project.name, issue.id, label.id])) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + issue = Issue.objects.get(pk=issue.pk) + self.assertTrue(label in issue.labels.all()) + self.assertEqual(issue.events.count(), count + 1) + response = self.client.get(reverse('remove-label-from-issue', args=[project.name, issue.id, label.id])) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + issue = Issue.objects.get(pk=issue.pk) + self.assertFalse(label in issue.labels.all()) + self.assertEqual(issue.events.count(), count + 2) - def test_issue_remove_label(self): - pass - - def test_issue_add_milestone(self): - pass - - def test_issue_remove_milestone(self): - pass + def test_issue_add_remove_milestone(self): + project = Project.objects.get(name='project-1') + issue = project.issues.get(title='Issue 1') + count = issue.events.count() + milestone = project.milestones.get(name='v1.0') + self.assertEqual(issue.milestone, None) + response = self.client.get(reverse('add-milestone-to-issue', args=[project.name, issue.id, milestone.name])) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + issue = Issue.objects.get(pk=issue.pk) + self.assertEqual(issue.milestone, milestone) + self.assertEqual(issue.events.count(), count + 1) + milestone = project.milestones.get(name='v2.0') + response = self.client.post(reverse('add-milestone', args=[project.name])+'?issue='+str(issue.id), { + 'name': 'new-milestone', + 'color': '#00ff00', + }, follow=True) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + project = Project.objects.get(pk=project.pk) + milestone = project.milestones.get(name='new-milestone') + issue = Issue.objects.get(pk=issue.pk) + self.assertEqual(issue.milestone, milestone) + self.assertEqual(issue.events.count(), count + 2) + response = self.client.get(reverse('remove-milestone-from-issue', args=[project.name, issue.id, milestone.name])) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + issue = Issue.objects.get(pk=issue.pk) + self.assertEqual(issue.milestone, None) + self.assertEqual(issue.events.count(), count + 3) def test_issue_subscribe_unsubscribe(self): self.client.logout() @@ -142,6 +340,9 @@ class TestViews(TestCase): issue = Issue.objects.get(title='Issue 1') project = issue.project self.assertFalse(user in issue.subscribers.all()) + response = self.client.get(reverse('unsubscribe-issue', args=[project.name, issue.id]), follow=True) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + self.assertContains(response, 'not subscribed to this issue') response = self.client.get(reverse('subscribe-issue', args=[project.name, issue.id])) self.assertRedirects(response, reverse('profile')) user.email = 'user@example.com' @@ -150,6 +351,9 @@ class TestViews(TestCase): self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) issue = Issue.objects.get(pk=issue.pk) self.assertTrue(user in issue.subscribers.all()) + response = self.client.get(reverse('subscribe-issue', args=[project.name, issue.id]), follow=True) + self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) + self.assertContains(response, 'already subscribed to this issue') response = self.client.get(reverse('unsubscribe-issue', args=[project.name, issue.id])) self.assertRedirects(response, reverse('show-issue', args=[project.name, issue.id])) issue = Issue.objects.get(pk=issue.pk) @@ -164,14 +368,29 @@ class TestViews(TestCase): def test_label_add(self): project = Project.objects.get(name='project-1') + count = project.labels.count() response = self.client.get(reverse('add-label', args=[project.name])) self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('add-label', args=[project.name]), { + 'name': 'test-label', + 'color': '#ff0000', + }) + self.assertRedirects(response, reverse('list-label', args=[project.name])) + project = Project.objects.get(pk=project.pk) + self.assertEqual(project.labels.count(), count + 1) def test_label_edit(self): project = Project.objects.get(name='project-1') label = project.labels.first() response = self.client.get(reverse('edit-label', args=[project.name, label.id])) self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('edit-label', args=[project.name, label.id]), { + 'name': 'new-label-name', + 'color': label.color, + }) + self.assertRedirects(response, reverse('list-label', args=[project.name])) + label = Label.objects.get(pk=label.pk) + self.assertEqual(label.name, 'new-label-name') def test_label_delete(self): count_active = Label.objects.filter(deleted=False).count() @@ -195,14 +414,27 @@ class TestViews(TestCase): def test_milestone_add(self): project = Project.objects.get(name='project-1') + count = project.milestones.count() response = self.client.get(reverse('add-milestone', args=[project.name])) self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('add-milestone', args=[project.name]), { + 'name': 'new-version', + }) + self.assertRedirects(response, reverse('list-milestone', args=[project.name])) + project = Project.objects.get(pk=project.pk) + self.assertEqual(project.milestones.count(), count + 1) def test_milestone_edit(self): project = Project.objects.get(name='project-1') milestone = project.milestones.first() response = self.client.get(reverse('edit-milestone', args=[project.name, milestone.name])) self.assertEqual(response.status_code, 200) + response = self.client.post(reverse('edit-milestone', args=[project.name, milestone.name]), { + 'name': 'new-milestone-name', + }) + self.assertRedirects(response, reverse('list-milestone', args=[project.name])) + milestone = Milestone.objects.get(pk=milestone.pk) + self.assertEqual(milestone.name, 'new-milestone-name') def test_milestone_close_reopen(self): milestone = Milestone.objects.filter(closed=False).first()