def setUp(self): # NOTE: these elements get modified by some testcases, so they should NOT be created in setUpTestData() self.project = Project(creator=self.user1, name_short='asdf') self.project.save() self.project.developer.add(self.user1) self.project.developer.add(self.user2) self.project.manager.add(self.user1) self.project2 = Project(creator=self.user2, name_short='asdg') self.project2.save() self.project2.manager.add(self.user2) self.issue = Issue(title='test', project=self.project) self.issue.save() self.issue2 = Issue(title='test', project=self.project2) self.issue2.save() self.comment = Comment(text='test', creator=self.user1, issue=self.issue) self.comment.save() self.comment2 = Comment(text='test', creator=self.user2, issue=self.issue2) self.comment2.save() self.log = Timelog(time=datetime.timedelta(hours=2), user=self.user1, issue=self.issue) self.log.save() self.log2 = Timelog(time=datetime.timedelta(hours=2), user=self.user2, issue=self.issue2) self.log2.save() self.user1_auth = 'Basic ' + base64.b64encode('user1:c'.encode()).decode() self.user2_auth = 'Basic ' + base64.b64encode('user2:c'.encode()).decode() self.client.credentials(HTTP_AUTHORIZATION=self.user1_auth)
def test_comment_delete(self): # create sample issue issue = Issue(title="Test-Issue", project=self.project, kanbancol=self.column, type="Bug") issue.save() # create sample comment comment = Comment(text="Test Comment", creator=self.user, issue=issue) comment.save() # delete the comment response = self.client.get(reverse('issue:delete_comment', kwargs={ 'project': self.project.name_short, 'sqn_i': issue.number, 'pk_c': comment.pk }), follow=True) self.assertRedirects( response, reverse('issue:detail', kwargs={ 'project': self.project.name_short, 'sqn_i': issue.number })) self.assertFalse(issue.comments.all().exists())
def test_comment_create(self): comment_text = "Fancy comment text" comment1 = Comment(creator=self.user, issue=self.issue, text=comment_text) comment1.save() self.assertEqual(Issue.objects.count(), 1) self.assertEqual(self.issue.comments.count(), 1) self.assertEqual(self.issue.comments.first().text, comment_text)
def test_redirect_to_login_and_login_required(self): # create comment + logout comment = Comment(text="comment text", creator=self.user, issue=self.issue) comment.save() self.client.logout() # edit comment-view redirect_to_login_and_login_required(self, 'issue:edit_comment', address_kwargs={'project': self.project.name_short, 'sqn_i': 1, 'pk_c': 1})
def test_view_and_template(self): # create comment comment = Comment(text="comment text", creator=self.user, issue=self.issue) comment.save() # edit comment-view view_and_template(self, IssueEditCommentView, 'comment/comment_edit.html', 'issue:edit_comment', address_kwargs={'project': self.project.name_short, 'sqn_i': 1, 'pk_c': 1}, get_kwargs={'text': "comment text"})
def test_comment_seqnum_stays_after_editing(self): self.assertEqual(self.issue.nextCommentId, 1) values = {'text': "comment text"} # create comment + logout comment = Comment(text=values['text'], creator=self.user, issue=self.issue) comment.save() issue = Issue.objects.get(pk=self.issue.pk) self.assertEqual(Comment.objects.count(), 1) self.assertEqual(Comment.objects.first().seqnum, 1) self.assertEqual(issue.comments.count(), 1) comment = issue.comments.first() self.assertEqual(comment.text, values['text']) self.assertEqual(issue.nextCommentId, 2) # check creator and time self.assertEqual(comment.creator, self.user) self.assertLess(comment.when, timezone.now()) self.assertGreater(comment.when, timezone.now() - timedelta(seconds=10)) values['text'] = "new comment text" # edit comment and assert that seqnum stays the same response = self.client.post( reverse('issue:edit_comment', kwargs={ 'project': self.project.name_short, 'sqn_i': 1, 'pk_c': comment.seqnum }), values) self.assertRedirects( response, reverse('issue:detail', kwargs={ 'project': self.project.name_short, 'sqn_i': 1 }) + '#comment1') response = self.client.get(response['location']) self.assertEqual(response.status_code, 200) issue = Issue.objects.get(pk=issue.pk) self.assertEqual(Comment.objects.count(), 1) self.assertEqual(Comment.objects.first().seqnum, 1) self.assertEqual(issue.comments.count(), 1) comment = issue.comments.first() self.assertEqual(comment.text, values['text']) self.assertEqual(issue.nextCommentId, 2)
def test_constraints(self): comment = Comment(creator=self.user2, issue=self.issuep2, text="blub, sehr kreativ", when=timezone.now()) comment.save() comment = Comment(creator=self.user, issue=self.issue, text="blub", when=timezone.now()) comment.save() # contains expressions and the expected size of the resulting queryset tests = { 'Project.name_short == "PRJ"': 0, 'Project.issue.title ~~ "Issue"': 1, 'Issue.type == "Bug"': 0, '(Issue.project.name_short ~~ "PR") OR (Issue.title ~~ "Bling")': 1, 'Comment.text ~~ "blub"': 1, 'Comment.text ~ "b.{2}b"': 1, } # use user2 for query this time (has only access to 2nd project) for t in tests: q = SearchFrontend.query(t, self.user2) self.assertEqual(len(q), tests[t]) self.assertEqual(Search.objects.filter(creator=self.user2, searchexpression=t).count(), 1)
def test_mute(self): self.client.force_login(self.user1) issue = Issue(title="asdf", project=self.project, creator=self.user1) issue.save() self.client.post( reverse("discussion:mute", kwargs={ "project": self.short, "sqn_i": issue.number })) Comment(creator=self.user2, issue=issue).save() res = self.client.get(reverse("discussion:list")) self.assertContains(res, "No unread messages.") # test next post parameter response = self.client.post(reverse("discussion:follow", kwargs={ "project": self.short, "sqn_i": issue.number }), {'next': '/timelog'}, follow=True) self.assertRedirects(response, reverse('timelog:loginfo')) response = self.client.post(reverse("discussion:mute", kwargs={ "project": self.short, "sqn_i": issue.number }), {'next': '/timelog'}, follow=True) self.assertRedirects(response, reverse('timelog:loginfo'))
def test_comment(self): self.client.force_login(self.user1) issue = Issue(title="asdf", project=self.project, creator=self.user1) issue.save() Comment(creator=self.user2, issue=issue).save() res = self.client.get(reverse("discussion:list")) self.assertContains(res, "asdf") # Now user2 should also be a participant and receive notifications self.client.force_login(self.user2) self.client.get( issue.get_absolute_url()) # Clear notification from issue creation Comment(creator=self.user1, issue=issue).save() res = self.client.get(reverse("discussion:list")) self.assertContains(res, "asdf") self.client.force_login(self.user1)
def setUp(self): self.project = Project(creator=self.user, name_short='PRJ') self.project.save() self.project.manager.add(self.user) # create issue, comment and attachment self.issue = Issue(title="Test-Issue", project=self.project, kanbancol=self.project.kanbancol.first(), type="Bug") self.issue.save() self.comment = Comment(issue=self.issue, creator=self.user) self.comment.save() self.attachment = Attachment(issue=self.issue, creator=self.user) self.attachment.save()
def setUp(self): # NOTE: these elements get modified by some testcases, so they should NOT be created in setUpTestData() self.project = Project(creator=self.user, name_short='PRJ') self.project.save() self.project.manager.add(self.user) # create issue, comment and attachment self.issue = Issue(title="Test-Issue", project=self.project, kanbancol=self.project.kanbancol.first(), type="Bug") self.issue.save() self.comment = Comment(issue=self.issue, creator=self.user) self.comment.save() self.attachment = Attachment(issue=self.issue, creator=self.user) self.attachment.save()
def issue_comment_send(request): issue = get_object_or_404(Issue, id=request.POST.get("issue", 0)) text = request.POST.get("comment") comment = Comment() comment.created_by = request.user comment.comment = text comment.issue = issue comment.save() return issue_poll(request)
def test_follow(self): issue = Issue(title="asdf", project=self.project, creator=self.user1) issue.save() self.client.force_login(self.user2) self.client.post( reverse("discussion:follow", kwargs={ "project": self.short, "sqn_i": issue.number })) Comment(creator=self.user1, issue=issue).save() res = self.client.get(reverse("discussion:list")) self.assertContains(res, "asdf")
def test_notification_types_and_mention_feature(self): self.client.force_login(self.user1) issue = Issue(title="asdf", project=self.project, creator=self.user1) issue.save() # mention with bullshit input Comment(creator=self.user1, issue=issue, text='@everybody').save() self.assertEqual( self.user2.notifications.get(issue=issue).type.filter( type='Mention').count(), 0) self.assertEqual( self.user1.notifications.filter(issue=issue).count(), 0) Comment(creator=self.user1, issue=issue, text='@thisisnousername').save() self.assertEqual( self.user2.notifications.get(issue=issue).type.filter( type='Mention').count(), 0) self.assertEqual( self.user1.notifications.filter(issue=issue).count(), 0) # NewIssue-Type in notification self.assertEqual(self.user2.notifications.first().type.first().type, 'NewIssue') Comment(creator=self.user1, issue=issue, text='mention @user2').save() # NewIssue-Type plus Mention-Type in notification self.assertEqual(self.user2.notifications.first().type.first().type, 'NewIssue') self.assertEqual(self.user2.notifications.first().type.last().type, 'Mention') # user1 is following the issue because he created it comm = Comment(creator=self.user2, issue=issue, text='lets make a comment') comm.save() self.assertEqual(self.user1.notifications.first().type.first().type, 'NewComment') self.assertEqual(self.user1.notifications.first().type.first().comment, comm) comm.text = 'edited comment' comm.save() # NewComment-Type got replaced by EditComment-Type self.assertEqual(self.user1.notifications.first().type.first().type, 'EditComment') self.assertEqual(self.user1.notifications.first().type.first().comment, comm) self.assertEqual(self.user1.notifications.first().type.count(), 1) comm.text = 'mention @user1"' comm.save() # NewComment-Type got replaced by Mention-Type self.assertEqual(self.user1.notifications.first().type.first().type, 'Mention') self.assertEqual(self.user1.notifications.first().type.first().comment, comm) self.assertEqual(self.user1.notifications.first().type.count(), 1) comm.text = 'mentionedited @user1"' comm.save() # still Mention-Type self.assertEqual(self.user1.notifications.first().type.first().type, 'Mention') self.assertEqual(self.user1.notifications.first().type.first().comment, comm) self.assertEqual(self.user1.notifications.first().type.count(), 1) # third user for project user3 = get_user_model().objects.create_user('user3', '*****@*****.**', 'c') self.project.developer.add(user3) issue2 = Issue(title="a new issue", project=self.project, creator=self.user1) issue2.save() self.assertEqual( user3.notifications.get(issue=issue2).type.filter( type="NewIssue").exists(), True) self.assertEqual( self.user2.notifications.get(issue=issue2).type.filter( type="NewIssue").exists(), True) comm2 = Comment(creator=self.user1, issue=issue2, text='@user2') comm2.save() comm2.text = 'lets make a comment with a all mention @all' comm2.save() # user1 created comment, mention for user2 and user3 self.assertEqual( user3.notifications.get(issue=issue2).type.filter( comment=comm2, type="Mention").exists(), True) self.assertEqual( self.user2.notifications.get(issue=issue2).type.filter( comment=comm2, type="Mention").exists(), True) self.assertEqual( self.user1.notifications.filter(issue=issue2).count(), 0) comm3 = Comment( creator=self.user2, issue=issue2, text='lets make a comment from user2 with a all mention @all') comm3.save() # user2 created comment, mention for user1 and user3 self.assertEqual( user3.notifications.get(issue=issue2).type.filter( type="Mention").count(), 2) self.assertEqual( self.user1.notifications.get(issue=issue2).type.filter( comment=comm3, type="Mention").exists(), True) self.assertEqual( self.user2.notifications.get(issue=issue2).type.filter( comment=comm3, type="Mention").count(), 0) issue3 = Issue(title="test multiple comment notifications", project=self.project, creator=self.user1) issue3.save() # instant mention self.user2.notifications.get(issue=issue3).delete() mention = Comment(creator=self.user1, issue=issue3, text='@user2') mention.save() self.assertEqual( self.user2.notifications.get(issue=issue3).type.filter( type="Mention", comment=mention).count(), 1) comm4 = Comment(creator=self.user2, issue=issue3, text='lets make a comment from user2') comm4.save() self.assertEqual( self.user1.notifications.get(issue=issue3).type.filter( type="NewComment").count(), 1) comm5 = Comment(creator=self.user2, issue=issue3, text='lets make another comment from user2') comm5.save() self.assertEqual( self.user1.notifications.get(issue=issue3).type.filter( type="NewComment").count(), 2) comm4.text = 'now a mention @user1' comm4.save() self.assertEqual( self.user1.notifications.get(issue=issue3).type.filter( type="NewComment").count(), 1) self.assertEqual( self.user1.notifications.get(issue=issue3).type.filter( type="Mention").count(), 1) comm5.text = 'now a mention @user1' comm5.save() self.assertEqual( self.user1.notifications.get(issue=issue3).type.filter( type="NewComment").count(), 0) self.assertEqual( self.user1.notifications.get(issue=issue3).type.filter( type="Mention").count(), 2) # test create comment trumped by edit comment trumped by mention comm6 = Comment(creator=self.user2, issue=issue2, text='lets make a comment from user2') comm6.save() self.assertEqual( self.user1.notifications.get(issue=issue2).type.filter( comment=comm6, type="NewComment").count(), 1) comm6.text = 'edited comment' comm6.save() self.assertEqual( self.user1.notifications.get(issue=issue2).type.filter( comment=comm6, type="NewComment").count(), 0) self.assertEqual( self.user1.notifications.get(issue=issue2).type.filter( comment=comm6, type="EditComment").count(), 1) # still one edit notification comm6.text = 'annother edit' comm6.save() self.assertEqual( self.user1.notifications.get(issue=issue2).type.filter( comment=comm6, type="EditComment").count(), 1) comm6.text = 'now a mention @user1' comm6.save() self.assertEqual( self.user1.notifications.get(issue=issue2).type.filter( comment=comm6, type="EditComment").count(), 0) self.assertEqual( self.user1.notifications.get(issue=issue2).type.filter( comment=comm6, type="Mention").count(), 1) number = comm6.seqnum # delete all notitypes for user1 on issue2 except the comm6 mention for notitype in self.user1.notifications.get(issue=issue2).type.all(): if notitype.comment.seqnum == number: continue else: notitype.delete() # delete mention comme notification object gets deletedd comm6.delete() self.assertEqual( self.user1.notifications.filter(issue=issue2).count(), 0) # test attachment filecontent = 'Hello World' temp = tempfile.NamedTemporaryFile(delete=False) temp.write(filecontent.encode()) temp.close() f = File(open(temp.name, 'r')) attachment = Attachment(file=f, creator=self.user2, issue=issue2) attachment.save() f.close() self.assertEqual( self.user1.notifications.get(issue=issue2).type.filter( type="NewAttachment").count(), 1) # delete the uploaded file from the server os.unlink(MEDIA_ROOT + '/' + attachment.file.name) # delete the uploaded file locally os.unlink(temp.name)
class ApiTest(APITestCase): @classmethod def setUpTestData(cls): # NOTE: if you modify these elements they need to be created in setUp(), instead of here cls.user1 = get_user_model().objects.create_user('user1', 'mail', 'c') cls.user2 = get_user_model().objects.create_user( 'user2', 'othermail', 'c') def setUp(self): # NOTE: these elements get modified by some testcases, so they should NOT be created in setUpTestData() self.project = Project(creator=self.user1, name_short='asdf') self.project.save() self.project.developer.add(self.user1) self.project.developer.add(self.user2) self.project.manager.add(self.user1) self.issue = Issue(title='test', project=self.project) self.issue.save() self.comment = Comment(text='test', creator=self.user1, issue=self.issue) self.comment.save() self.log = Timelog(time=datetime.timedelta(hours=2), user=self.user1, issue=self.issue) self.log.save() self.client.credentials(HTTP_AUTHORIZATION='Basic ' + base64.b64encode('user1:c'.encode()).decode()) def test_get_issues(self): response = self.client.get(reverse('api:issues-list')) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('count'), 0) issue = Issue(title='asdf', project=self.project) issue.save() issue.assignee.add(self.user1) response = self.client.get(reverse('api:issues-list')) self.assertEqual(response.json().get('count'), 1) issue = Issue(title='asdf2', project=self.project) issue.save() issue.assignee.add(self.user2) response = self.client.get(reverse('api:issues-list')) self.assertEqual(response.json().get('count'), 1) def test_get_projects(self): response = self.client.get(reverse('api:project-list')) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('count'), 1) def test_get_timelogs(self): response = self.client.get(reverse('api:timelogs-list')) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('count'), 1) issue = Issue(title='asdf', project=self.project) issue.save() log = Timelog(issue=issue, user=self.user1, time=datetime.timedelta(hours=2)) log.save() response = self.client.get(reverse('api:timelogs-list')) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('count'), 2) def test_get_users(self): response = self.client.get(reverse('api:customuser-list')) self.assertEqual(response.json().get('count'), 2) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_get_users_detail(self): response = self.client.get( reverse('api:customuser-detail', kwargs={'username': self.user1.username})) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIn(self.user1.username, response.json().get('username')) def test_post_project(self): project_data = {'name': 'yoflow', 'name_short': 'nanu'} response = self.client.post(reverse('api:project-list'), project_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) response = self.client.get(reverse('api:project-list')) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('count'), 2) def test_get_project_detail(self): response = self.client.get( reverse('api:project-detail', kwargs={'name_short': self.project.name_short})) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_patch_project_detail(self): project_data = { 'name': 'yoflow', } response = self.client.patch(reverse( 'api:project-detail', kwargs={'name_short': self.project.name_short}), data=project_data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('name'), 'yoflow') self.assertEqual(response.json().get('name_short'), 'asdf') # assert - at least one project manager project_data.update({'manager': [], 'developer': []}) response = self.client.patch(reverse( 'api:project-detail', kwargs={'name_short': self.project.name_short}), data=project_data, format='json') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_put_project_detail(self): project_data = { 'manager': ['user1'], 'name': 'yoflow', } response = self.client.put(reverse( 'api:project-detail', kwargs={'name_short': self.project.name_short}), data=project_data, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('name'), 'yoflow') def test_delete_project_detail(self): response = self.client.delete( reverse('api:project-detail', kwargs={'name_short': self.project.name_short})) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_get_project_issues(self): response = self.client.get( reverse('api:project_issues-list', kwargs={'project': self.project.name_short})) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_post_project_issues(self): issue_data = { 'title': 'this is a issue', } response = self.client.post(reverse( 'api:project_issues-list', kwargs={'project': self.project.name_short}), data=issue_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_get_project_timelogs(self): response = self.client.get( reverse('api:project_timelogs-list', kwargs={'project': self.project.name_short})) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_get_project_issue_detail(self): response = self.client.get( reverse('api:project_issues-detail', kwargs={ 'project': self.project.name_short, 'number': self.issue.number })) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.get( reverse('api:project_issues-list', kwargs={'project': self.project.name_short})) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_get_project_timelogs(self): response = self.client.get( reverse('api:project_timelogs-list', kwargs={'project': self.project.name_short})) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_get_project_issue_detail(self): response = self.client.get( reverse('api:project_issues-detail', kwargs={ 'project': self.project.name_short, 'number': self.issue.number })) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_put_project_issue_detail(self): issue_data = { 'title': 'this is a issue', } response = self.client.put( reverse('api:project_issues-detail', kwargs={ 'project': self.project.name_short, 'number': self.issue.number }), issue_data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('title'), 'this is a issue') def test_patch_project_issue_detail(self): issue_data = { 'title': 'this is a issue', } response = self.client.patch( reverse('api:project_issues-detail', kwargs={ 'project': self.project.name_short, 'number': self.issue.number }), issue_data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('title'), 'this is a issue') def test_delete_project_issue_detail(self): response = self.client.delete( reverse('api:project_issues-detail', kwargs={ 'project': self.project.name_short, 'number': self.issue.number })) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_get_project_issue_comments(self): response = self.client.get( reverse('api:project_issues_comments-list', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number })) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_post_project_issue_comments(self): comment_data = {'text': 'good evening'} response = self.client.post( reverse('api:project_issues_comments-list', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number }), comment_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_get_project_issue_timelogs(self): response = self.client.get( reverse('api:project_issues_timelogs-list', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number })) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_post_project_issue_timelogs(self): timelog_data = {'time': '2h'} response = self.client.post( reverse('api:project_issues_timelogs-list', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number }), timelog_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_get_project_issue_comments_detail(self): response = self.client.get( reverse('api:project_issues_comments-detail', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number, 'seqnum': self.comment.seqnum })) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_put_project_issue_comments_detail(self): comment_data = {'text': 'new content'} response = self.client.put( reverse('api:project_issues_comments-detail', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number, 'seqnum': self.comment.seqnum }), comment_data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('text'), 'new content') def test_patch_project_issue_comments_detail(self): comment_data = {'text': 'new content'} response = self.client.patch( reverse('api:project_issues_comments-detail', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number, 'seqnum': self.comment.seqnum }), comment_data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('text'), 'new content') def test_delete_project_issue_comments_detail(self): response = self.client.delete( reverse('api:project_issues_comments-detail', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number, 'seqnum': self.comment.seqnum })) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_get_project_issue_timelogs_detail(self): response = self.client.get( reverse('api:project_issues_timelogs-detail', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number, 'number': self.log.number })) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_put_project_issue_timelogs_detail(self): log_data = {'time': '4h10m'} response = self.client.put( reverse('api:project_issues_timelogs-detail', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number, 'number': self.log.number }), log_data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('time'), '4h 10m') def test_patch_project_issue_timelogs_detail(self): log_data = {'time': '4h10m'} response = self.client.patch( reverse('api:project_issues_timelogs-detail', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number, 'number': self.log.number }), log_data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json().get('time'), '4h 10m') def test_delete_project_issue_timelogs_detail(self): response = self.client.delete( reverse('api:project_issues_timelogs-detail', kwargs={ 'project': self.project.name_short, 'issue': self.issue.number, 'number': self.log.number })) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
class ApiPermissionTest(APITestCase): @classmethod def setUpTestData(cls): # NOTE: if you modify those elements they need to be created in setUp(), instead of here cls.user1 = get_user_model().objects.create_user('user1', 'mail', 'c') cls.user2 = get_user_model().objects.create_user('user2', 'othermail', 'c') def setUp(self): # NOTE: these elements get modified by some testcases, so they should NOT be created in setUpTestData() self.project = Project(creator=self.user1, name_short='asdf') self.project.save() self.project.developer.add(self.user1) self.project.developer.add(self.user2) self.project.manager.add(self.user1) self.project2 = Project(creator=self.user2, name_short='asdg') self.project2.save() self.project2.manager.add(self.user2) self.issue = Issue(title='test', project=self.project) self.issue.save() self.issue2 = Issue(title='test', project=self.project2) self.issue2.save() self.comment = Comment(text='test', creator=self.user1, issue=self.issue) self.comment.save() self.comment2 = Comment(text='test', creator=self.user2, issue=self.issue2) self.comment2.save() self.log = Timelog(time=datetime.timedelta(hours=2), user=self.user1, issue=self.issue) self.log.save() self.log2 = Timelog(time=datetime.timedelta(hours=2), user=self.user2, issue=self.issue2) self.log2.save() self.user1_auth = 'Basic ' + base64.b64encode('user1:c'.encode()).decode() self.user2_auth = 'Basic ' + base64.b64encode('user2:c'.encode()).decode() self.client.credentials(HTTP_AUTHORIZATION=self.user1_auth) def try_project_put_patch_delete(self, expected): project_data = { 'name': 'yoflow', } response = self.client.patch(reverse('api:project-detail', kwargs={'name_short': self.project.name_short}), data=project_data) self.assertEqual(response.status_code, expected) response = self.client.put(reverse('api:project-detail', kwargs={'name_short': self.project.name_short}), data=project_data) self.assertEqual(response.status_code, expected) response = self.client.delete(reverse('api:project-detail', kwargs={'name_short': self.project.name_short})) self.assertEqual(response.status_code, expected) def test_project_permissions(self): # project1 granted response = self.client.get(reverse('api:project-detail', kwargs={'name_short': self.project.name_short})) self.assertEqual(response.status_code, status.HTTP_200_OK) # project2 denied for user1 response = self.client.get(reverse('api:project-detail', kwargs={'name_short': self.project2.name_short})) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) # project2 granted for user2 self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth) response = self.client.get(reverse('api:project-detail', kwargs={'name_short': self.project2.name_short})) self.assertEqual(response.status_code, status.HTTP_200_OK) # project1 user2 put, patch, delete denied (no manager) self.try_project_put_patch_delete(status.HTTP_403_FORBIDDEN) # no credentials self.client.credentials() self.try_project_put_patch_delete(status.HTTP_401_UNAUTHORIZED) def test_project_issues_get_post_permissions(self): issue_data = { 'title': 'laalalla' } # project1 granted response = self.client.get(reverse('api:project_issues-list', kwargs={'project': self.project.name_short})) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.post(reverse('api:project_issues-list', kwargs={'project': self.project.name_short}), issue_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # project2 denied for user1 response = self.client.get(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short})) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) response = self.client.post(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short}), issue_data) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) # project2 granted for user2 self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth) response = self.client.get(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short})) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.post(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short}), issue_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # no credentials self.client.credentials() response = self.client.get(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short})) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) response = self.client.post(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short}), issue_data) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) def try_issue_put_patch_delete(self, expected): issue_data = { 'title': 'yoflow', } url = 'api:project_issues-detail' response = self.client.get(reverse(url, kwargs={'project': self.project2.name_short, 'number': self.issue2.number})) self.assertIn(response.status_code, expected) response = self.client.patch(reverse(url, kwargs={'project': self.project2.name_short, 'number': self.issue2.number}), data=issue_data) self.assertIn(response.status_code, expected) response = self.client.put(reverse(url, kwargs={'project': self.project2.name_short, 'number': self.issue2.number}), data=issue_data) self.assertIn(response.status_code, expected) response = self.client.delete(reverse(url, kwargs={'project': self.project2.name_short, 'number': self.issue2.number})) self.assertIn(response.status_code, expected) def test_project_issues_detail_put_patch_delete_permissions(self): # user1 not in project1 self.try_issue_put_patch_delete([status.HTTP_403_FORBIDDEN]) # user2 in project2 self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth) self.try_issue_put_patch_delete([status.HTTP_200_OK, status.HTTP_204_NO_CONTENT]) # not credentials self.client.credentials() self.try_issue_put_patch_delete([status.HTTP_401_UNAUTHORIZED]) def test_project_issue_comments_get_post_permissions(self): comment_data = { 'text': 'laalalla' } # project1 granted response = self.client.get(reverse('api:project_issues_comments-list', kwargs={'project': self.project.name_short, 'issue': self.issue.number})) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.post(reverse('api:project_issues_comments-list', kwargs={'project': self.project.name_short, 'issue': self.issue.number}), comment_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # project2 denied for user1 response = self.client.get(reverse('api:project_issues_comments-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number})) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) response = self.client.post(reverse('api:project_issues_comments-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}), comment_data) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) # project2 granted for user2 self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth) response = self.client.get(reverse('api:project_issues_comments-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number})) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.post(reverse('api:project_issues_comments-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}), comment_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # no credentials self.client.credentials() response = self.client.get(reverse('api:project_issues_comments-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number})) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) response = self.client.post(reverse('api:project_issues_comments-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}), comment_data) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) def try_issue_comments_put_patch_delete(self, expected): comment_data = { 'text': 'lalala', } url = 'api:project_issues_comments-detail' response = self.client.get(reverse(url, kwargs={'project': self.project2.name_short, 'issue': self.issue2.number, 'seqnum': self.comment2.seqnum})) self.assertIn(response.status_code, expected) response = self.client.patch(reverse(url, kwargs={'project': self.project2.name_short, 'issue': self.issue2.number, 'seqnum': self.comment2.seqnum}), data=comment_data) self.assertIn(response.status_code, expected) response = self.client.put(reverse(url, kwargs={'project': self.project2.name_short, 'issue': self.issue2.number, 'seqnum': self.comment2.seqnum}), data=comment_data) self.assertIn(response.status_code, expected) response = self.client.delete(reverse(url, kwargs={'project': self.project2.name_short, 'issue': self.issue2.number, 'seqnum': self.comment2.seqnum})) self.assertIn(response.status_code, expected) def test_project_issues_comments_detail_put_patch_delete_permissions(self): # TODO TESTCASE difference manager/not manager # user1 not in project1 self.try_issue_comments_put_patch_delete([status.HTTP_403_FORBIDDEN]) self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth) # user2 in project2 self.try_issue_comments_put_patch_delete([status.HTTP_200_OK, status.HTTP_204_NO_CONTENT]) self.client.credentials() self.try_issue_comments_put_patch_delete([status.HTTP_401_UNAUTHORIZED]) def test_project_issue_timelogs_get_post_permissions(self): log_data = { 'time': '2h5m' } # project1 granted response = self.client.get(reverse('api:project_issues_timelogs-list', kwargs={'project': self.project.name_short, 'issue': self.issue.number})) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.post(reverse('api:project_issues_timelogs-list', kwargs={'project': self.project.name_short, 'issue': self.issue.number}), log_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # project2 denied for user1 response = self.client.get(reverse('api:project_issues_timelogs-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number})) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) response = self.client.post(reverse('api:project_issues_timelogs-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}), log_data) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) # project2 granted for user2 self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth) response = self.client.get(reverse('api:project_issues_timelogs-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number})) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.post(reverse('api:project_issues_timelogs-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}), log_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) # no credentials self.client.credentials() response = self.client.get(reverse('api:project_issues_timelogs-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number})) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) response = self.client.post(reverse('api:project_issues_timelogs-list', kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}), log_data) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) # helper function def try_issue_timelogs_put_patch_delete(self, expected): log_data = { 'time': '2h5m' } url = 'api:project_issues_timelogs-detail' response = self.client.get(reverse(url, kwargs={'project': self.project2.name_short, 'issue': self.issue2.number, 'number': self.log2.number})) self.assertIn(response.status_code, expected) response = self.client.patch(reverse(url, kwargs={'project': self.project2.name_short, 'issue': self.issue2.number, 'number': self.log2.number}), data=log_data) self.assertIn(response.status_code, expected) response = self.client.put(reverse(url, kwargs={'project': self.project2.name_short, 'issue': self.issue2.number, 'number': self.log2.number}), data=log_data) self.assertIn(response.status_code, expected) response = self.client.delete(reverse(url, kwargs={'project': self.project2.name_short, 'issue': self.issue2.number, 'number': self.log2.number})) self.assertIn(response.status_code, expected) def test_project_issues_timelogs_detail_put_patch_delete_permissions(self): # TODO TESTCASE difference manager/not manager # user1 not in project1 self.try_issue_timelogs_put_patch_delete([status.HTTP_403_FORBIDDEN]) self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth) # user2 in project2 self.try_issue_timelogs_put_patch_delete([status.HTTP_200_OK, status.HTTP_204_NO_CONTENT]) self.client.credentials() self.try_issue_timelogs_put_patch_delete([status.HTTP_401_UNAUTHORIZED])
class IssueSearchTest(TestCase): @classmethod def setUpTestData(cls): # NOTE: if you modify those elements they need to be created in setUp, instead of here cls.user = get_user_model().objects.create_user('a', 'b', 'c') def setUp(self): self.project = Project(creator=self.user, name_short='PRJ') self.project.save() self.project.manager.add(self.user) # create issue, comment and attachment self.issue = Issue(title="Test-Issue", project=self.project, kanbancol=self.project.kanbancol.first(), type="Bug") self.issue.save() self.comment = Comment(issue=self.issue, creator=self.user) self.comment.save() self.attachment = Attachment(issue=self.issue, creator=self.user) self.attachment.save() def test_check_credentials(self): for i in [self.project, self.issue, self.comment, self.attachment]: self.assertEqual( getattr(i, 'user_has_read_permissions')(self.user), 1) self.assertEqual( getattr(i, 'user_has_write_permissions')(self.user), 1) # remove write permissions user2 = get_user_model().objects.create_user('d', 'e', 'f') self.project.developer.add(self.user) self.project.manager.remove(self.user) self.comment.creator = user2 self.comment.save() self.attachment.creator = user2 self.attachment.save() # issue and project do distinguish between read and write permissions for i in [self.project, self.issue]: self.assertEqual( getattr(i, 'user_has_read_permissions')(self.user), 1) self.assertEqual( getattr(i, 'user_has_write_permissions')(self.user), 0) for i in [self.comment, self.attachment]: self.assertEqual( getattr(i, 'user_has_read_permissions')(self.user), 1) self.assertEqual( getattr(i, 'user_has_write_permissions')(self.user), 0) # remove read permissions self.project.developer.remove(self.user) for i in [self.project, self.issue, self.comment, self.attachment]: self.assertEqual( getattr(i, 'user_has_read_permissions')(self.user), 0) self.assertEqual( getattr(i, 'user_has_write_permissions')(self.user), 0)
def test_user_passes_test_mixin(self): proj_name2 = "project" proj_short2 = "cccc" project2 = Project(name=proj_name2, name_short=proj_short2, creator=self.user) project2.save() issue = Issue(title="p1-iss", project=self.project) issue.save() issue2 = Issue(title="p2-iss", project=project2) issue2.save() comment_text = "Fancy comment text" comment_edit = "EDITED AND CHANGED COMMENT" new_comment = {'action': "commentAtt", 'text': comment_text} edit_comment = {'text': comment_edit} comment1 = Comment(creator=self.user, issue=issue, text=comment_text) comment1.save() comment2 = Comment(creator=self.user, issue=issue2, text=comment_text) comment2.save() self.client.logout() self.client.force_login(self.user2) # developer is good self.project.developer.add(self.user2) self.project.save() # create response = self.client.post(reverse('issue:detail', kwargs={ 'project': self.project.name_short, 'sqn_i': issue.number }), new_comment, follow=True) self.assertNotContains( response, "Your account doesn't have access to this page. To proceed, please " + "login with an account that has access.") self.assertEqual(issue.comments.count(), 2) # edit # developer can edit only their own comments response = self.client.post(reverse('issue:edit_comment', kwargs={ 'project': self.project.name_short, 'sqn_i': issue.number, 'pk_c': 2 }), edit_comment, follow=True) self.assertNotContains( response, "Your account doesn't have access to this page. To proceed, please " + "login with an account that has access.") self.assertEqual(issue.comments.count(), 2) self.assertEqual(issue.comments.get(seqnum=2).text, comment_edit) # manager is good project2.manager.add(self.user2) project2.save() # create response = self.client.post(reverse('issue:detail', kwargs={ 'project': proj_short2, 'sqn_i': 1 }), new_comment, follow=True) self.assertNotContains( response, "Your account doesn't have access to this page. To proceed, please " + "login with an account that has access.") self.assertEqual(issue2.comments.count(), 2) # edit # even manager can edit only their own comments response = self.client.post( reverse('issue:edit_comment', kwargs={ 'project': proj_short2, 'sqn_i': 1, 'pk_c': 2 }), # TODO pkc=1 probieren s.o edit_comment, follow=True) self.assertNotContains( response, "Your account doesn't have access to this page. To proceed, please " + "login with an account that has access.") self.assertEqual(issue2.comments.count(), 2) self.assertEqual(issue2.comments.get(seqnum=2).text, comment_edit)