def setUp(self): self.default_state = create_state() self.nondefault_state = create_state() self.patch = read_patch(self.patch_filename) self.user = create_user() self.project = create_project()
def test_utf8_path(self): project = utils.create_project() utils.create_state() path = os.path.join(TEST_MAIL_DIR, '0013-with-utf8-body.mbox') call_command('parsemail', infile=path, list_id=project.listid) count = models.Patch.objects.filter(project=project.id).count() self.assertEqual(count, 1)
def test_valid_path(self): project = utils.create_project() utils.create_state() path = os.path.join(TEST_MAIL_DIR, '0001-git-pull-request.mbox') with self.assertRaises(SystemExit) as exc: call_command('parsemail', infile=path, list_id=project.listid) self.assertEqual(exc.exception.code, 0) count = models.Patch.objects.filter(project=project.id).count() self.assertEqual(count, 1)
def test_dup_mail(self): project = utils.create_project() utils.create_state() path = os.path.join(TEST_MAIL_DIR, '0001-git-pull-request.mbox') call_command('parsemail', infile=path, list_id=project.listid) count = models.Patch.objects.filter(project=project.id).count() self.assertEqual(count, 1) # the parser should return None, not throwing an exception # as this is a pretty normal part of life on a busy site call_command('parsemail', infile=path, list_id=project.listid)
def test_valid_stdin(self): project = utils.create_project() utils.create_state() path = os.path.join(TEST_MAIL_DIR, '0001-git-pull-request.mbox') sys.stdin.close() sys.stdin = open(path) call_command('parsemail', infile=None, list_id=project.listid) sys.stdin.close() count = models.Patch.objects.filter(project=project.id).count() self.assertEqual(count, 1)
def test_utf8_stdin(self): project = utils.create_project() utils.create_state() path = os.path.join(TEST_MAIL_DIR, '0013-with-utf8-body.mbox') sys.stdin.close() sys.stdin = open(path) with self.assertRaises(SystemExit) as exc: call_command('parsemail', infile=None, list_id=project.listid) self.assertEqual(exc.exception.code, 0) count = models.Patch.objects.filter(project=project.id).count() self.assertEqual(count, 1)
def test_list_filter_state(self): """Filter patches by state.""" self._create_patch() user = create_user() state_obj_b = create_state(name='New') create_patch(state=state_obj_b) state_obj_c = create_state(name='RFC') create_patch(state=state_obj_c) self.client.force_authenticate(user=user) resp = self.client.get(self.api_url(), [('state', 'under-review'), ('state', 'new')]) self.assertEqual(2, len(resp.data))
def test_list(self): """Validate we can list a patch.""" resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(0, len(resp.data)) state_obj = create_state(name='Under Review') patch_obj = create_patch(state=state_obj) # anonymous user resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) patch_rsp = resp.data[0] self.assertSerialized(patch_obj, patch_rsp) self.assertNotIn('headers', patch_rsp) self.assertNotIn('content', patch_rsp) self.assertNotIn('diff', patch_rsp) # test filtering by state resp = self.client.get(self.api_url(), {'state': 'under-review'}) self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), {'state': 'missing-state'}) self.assertEqual(0, len(resp.data)) # authenticated user user = create_user() self.client.force_authenticate(user=user) resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) patch_rsp = resp.data[0] self.assertSerialized(patch_obj, patch_rsp)
def test_state_change_valid(self): state = create_state() self._test_state_change(state.pk) for patch in [Patch.objects.get(pk=p.pk) for p in self.patches]: self.assertEqual(patch.state, state)
def test_unexpired_notification_merge(self): """Test that when there are multiple pending notifications, with at least one within the notification delay, that other notifications are held""" patches = create_patches(2, project=self.project) for patch in patches: patch.save() PatchChangeNotification(patch=patch, orig_state=patch.state).save() state = create_state() self.assertEqual(PatchChangeNotification.objects.count(), len(patches)) self._expire_notifications() # update one notification, to bring it out of the notification delay patches[0].state = state patches[0].save() # the updated notification should prevent the other from being sent errors = send_notifications() self.assertEqual(errors, []) self.assertEqual(len(mail.outbox), 0) # expire the updated notification self._expire_notifications() errors = send_notifications() self.assertEqual(errors, []) self.assertEqual(len(mail.outbox), 1) msg = mail.outbox[0] for patch in patches: self.assertIn(patch.get_absolute_url(), msg.body)
def test_update_maintainer(self): """Update patch as maintainer. Ensure updates can be performed by maintainers. """ project = create_project() patch = create_patch(project=project) state = create_state() user = create_maintainer(project) self.client.force_authenticate(user=user) resp = self.client.patch(self.api_url(patch.id), { 'state': state.slug, 'delegate': user.id }) self.assertEqual(status.HTTP_200_OK, resp.status_code, resp) self.assertEqual(Patch.objects.get(id=patch.id).state, state) self.assertEqual(Patch.objects.get(id=patch.id).delegate, user) # (who can unset fields too) # we need to send as JSON due to https://stackoverflow.com/q/30677216/ resp = self.client.patch(self.api_url(patch.id), {'delegate': None}, format='json') self.assertEqual(status.HTTP_200_OK, resp.status_code, resp) self.assertIsNone(Patch.objects.get(id=patch.id).delegate)
def _create_events(self): """Create sample events. This one's a bit weird. While we could generate event models ourselves, it seems wiser to test the event machinery as many times as possible. As a result, we actually create a load of *other* objects, which will raise signals and trigger the remainder. """ # series-created series = create_series() # patch-created, patch-completed, series-completed patch = create_patch(series=series) # cover-created create_cover(series=series) # check-created create_check(patch=patch) # patch-delegated, patch-state-changed actor = create_maintainer(project=patch.project) user = create_maintainer(project=patch.project) state = create_state() patch.delegate = user patch.state = state self.assertTrue(patch.is_editable(actor)) patch.save() return Event.objects.all()
def test_update(self): """Ensure updates can be performed by maintainers.""" project = create_project() patch = create_patch(project=project) state = create_state() # anonymous user resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) # authenticated user user = create_user() self.client.force_authenticate(user=user) resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) # maintainer user = create_maintainer(project) self.client.force_authenticate(user=user) resp = self.client.patch(self.api_url(patch.id), { 'state': state.name, 'delegate': user.id}) self.assertEqual(status.HTTP_200_OK, resp.status_code, resp) self.assertEqual(Patch.objects.get(id=patch.id).state, state) self.assertEqual(Patch.objects.get(id=patch.id).delegate, user) # (who can unset fields too) # we need to send as JSON due to https://stackoverflow.com/q/30677216/ resp = self.client.patch(self.api_url(patch.id), {'delegate': None}, format='json') self.assertEqual(status.HTTP_200_OK, resp.status_code, resp) self.assertIsNone(Patch.objects.get(id=patch.id).delegate)
def _create_patch(self, **kwargs): person_obj = create_person(email='*****@*****.**') project_obj = create_project(linkname='myproject') state_obj = create_state(name='Under Review') patch_obj = create_patch(state=state_obj, project=project_obj, submitter=person_obj, **kwargs) return patch_obj
def test_notifications_disabled(self): """Ensure we don't see notifications created when a project is configured not to send them""" patch = create_patch() # don't use self.project state = create_state() patch.state = state patch.save() self.assertEqual(PatchChangeNotification.objects.count(), 0)
def test_update_anonymous(self): """Update patch as anonymous user. Ensure updates can be performed by maintainers. """ patch = create_patch() state = create_state() resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
def test_update_non_maintainer(self): """Update patch as non-maintainer. Ensure updates can be performed by maintainers. """ patch = create_patch() state = create_state() user = create_user() self.client.force_authenticate(user=user) resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
def test_notification_updated(self): """Ensure we update notifications when the patch has a second change, but keep the original patch details""" patch = create_patch(project=self.project) oldstate = patch.state newstates = [create_state(), create_state()] patch.state = newstates[0] patch.save() self.assertEqual(PatchChangeNotification.objects.count(), 1) notification = PatchChangeNotification.objects.all()[0] self.assertEqual(notification.orig_state, oldstate) orig_timestamp = notification.last_modified patch.state = newstates[1] patch.save() self.assertEqual(PatchChangeNotification.objects.count(), 1) notification = PatchChangeNotification.objects.all()[0] self.assertEqual(notification.orig_state, oldstate) self.assertTrue(notification.last_modified >= orig_timestamp)
def test_list(self): """Validate we can list a patch.""" resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(0, len(resp.data)) person_obj = create_person(email='*****@*****.**') state_obj = create_state(name='Under Review') project_obj = create_project(linkname='myproject') patch_obj = create_patch(state=state_obj, project=project_obj, submitter=person_obj) # anonymous user resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) patch_rsp = resp.data[0] self.assertSerialized(patch_obj, patch_rsp) self.assertNotIn('headers', patch_rsp) self.assertNotIn('content', patch_rsp) self.assertNotIn('diff', patch_rsp) # authenticated user user = create_user() self.client.force_authenticate(user=user) resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) patch_rsp = resp.data[0] self.assertSerialized(patch_obj, patch_rsp) # test filtering by state resp = self.client.get(self.api_url(), {'state': 'under-review'}) self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), {'state': 'missing-state'}) self.assertEqual(0, len(resp.data)) # test filtering by project resp = self.client.get(self.api_url(), {'project': 'myproject'}) self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), {'project': 'invalidproject'}) self.assertEqual(0, len(resp.data)) # test filtering by submitter, both ID and email resp = self.client.get(self.api_url(), {'submitter': person_obj.id}) self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), {'submitter': '*****@*****.**'}) self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), {'submitter': '*****@*****.**'}) self.assertEqual(0, len(resp.data))
def test_list(self): """Validate we can list a patch.""" resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(0, len(resp.data)) person_obj = create_person(email='*****@*****.**') state_obj = create_state(name='Under Review') project_obj = create_project(linkname='myproject') patch_obj = create_patch(state=state_obj, project=project_obj, submitter=person_obj) # anonymous user resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) patch_rsp = resp.data[0] self.assertSerialized(patch_obj, patch_rsp) self.assertNotIn('headers', patch_rsp) self.assertNotIn('content', patch_rsp) self.assertNotIn('diff', patch_rsp) # authenticated user user = create_user() self.client.force_authenticate(user=user) resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) patch_rsp = resp.data[0] self.assertSerialized(patch_obj, patch_rsp) # test filtering by state resp = self.client.get(self.api_url(), {'state': 'under-review'}) self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), {'state': 'missing-state'}) self.assertEqual(0, len(resp.data)) # test filtering by project resp = self.client.get(self.api_url(), {'project': 'myproject'}) self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), {'project': 'invalidproject'}) self.assertEqual(0, len(resp.data)) # test filtering by submitter, both ID and email resp = self.client.get(self.api_url(), {'submitter': person_obj.id}) self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), { 'submitter': '*****@*****.**'}) self.assertEqual([patch_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), { 'submitter': '*****@*****.**'}) self.assertEqual(0, len(resp.data))
def test_patch_change(self): """Ensure we get a notification for interesting patch changes""" patch = create_patch(project=self.project) oldstate = patch.state state = create_state() patch.state = state patch.save() self.assertEqual(PatchChangeNotification.objects.count(), 1) notification = PatchChangeNotification.objects.all()[0] self.assertEqual(notification.patch, patch) self.assertEqual(notification.orig_state, oldstate)
def test_update_invalid(self): """Ensure we handle invalid Patch states.""" project = create_project() state = create_state() patch = create_patch(project=project, state=state) user = create_maintainer(project) # invalid state self.client.force_authenticate(user=user) resp = self.client.patch(self.api_url(patch.id), {'state': 'foobar'}) self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code) self.assertContains(resp, 'Expected one of: %s.' % state.name, status_code=status.HTTP_400_BAD_REQUEST)
def test_notification_cancelled(self): """Ensure we cancel notifications that are no longer valid""" patch = create_patch(project=self.project) oldstate = patch.state state = create_state() patch.state = state patch.save() self.assertEqual(PatchChangeNotification.objects.count(), 1) patch.state = oldstate patch.save() self.assertEqual(PatchChangeNotification.objects.count(), 0)
def test_update_maintainer_version_1_0(self): """Update patch as maintainer on v1.1.""" project = create_project() patch = create_patch(project=project) state = create_state() user = create_maintainer(project) self.client.force_authenticate(user=user) resp = self.client.patch(self.api_url(patch.id, version="1.1"), { 'state': state.slug, 'delegate': user.id }) self.assertEqual(status.HTTP_200_OK, resp.status_code, resp) self.assertEqual(Patch.objects.get(id=patch.id).state, state) self.assertEqual(Patch.objects.get(id=patch.id).delegate, user)
def test_patch_state_changed(self): patch = utils.create_patch() old_state = patch.state new_state = utils.create_state() patch.state = new_state patch.save() events = _get_events(patch=patch) self.assertEqual(events.count(), 2) # we don't care about the CATEGORY_PATCH_CREATED event here self.assertEqual(events[1].category, Event.CATEGORY_PATCH_STATE_CHANGED) self.assertEqual(events[1].project, patch.project) self.assertEventFields(events[1], previous_state=old_state, current_state=new_state)
def test_patch_state_changed(self): # purposefully setting series to None to minimize additional events patch = utils.create_patch(series=None) old_state = patch.state new_state = utils.create_state() patch.state = new_state patch.save() events = _get_events(patch=patch) self.assertEqual(events.count(), 2) # we don't care about the CATEGORY_PATCH_CREATED event here self.assertEqual(events[1].category, Event.CATEGORY_PATCH_STATE_CHANGED) self.assertEqual(events[1].project, patch.project) self.assertEventFields(events[1], previous_state=old_state, current_state=new_state)
def test_update_invalid_delegate(self): """Update patch with invalid fields. Ensure we handle invalid Patch updates. """ project = create_project() state = create_state() patch = create_patch(project=project, state=state) user_a = create_maintainer(project) user_b = create_user() self.client.force_authenticate(user=user_a) resp = self.client.patch(self.api_url(patch.id), {'delegate': user_b.id}) self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code) self.assertContains(resp, "User '%s' is not a maintainer" % user_b, status_code=status.HTTP_400_BAD_REQUEST)
def test_update(self): """Ensure updates can be performed by maintainers.""" project = create_project() patch = create_patch(project=project) state = create_state() # anonymous user resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) # authenticated user user = create_user() self.client.force_authenticate(user=user) resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) # maintainer user = create_maintainer(project) self.client.force_authenticate(user=user) resp = self.client.patch(self.api_url(patch.id), {'state': state.name}) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(Patch.objects.get(id=patch.id).state, state)
def test_update_legacy_delegate(self): """Regression test for bug #313.""" project = create_project() state = create_state() patch = create_patch(project=project, state=state) user_a = create_maintainer(project) # create a user (User), then delete the associated UserProfile and save # the user to ensure a new profile is generated user_b = create_user() self.assertEqual(user_b.id, user_b.profile.id) user_b.profile.delete() user_b.save() user_b.profile.maintainer_projects.add(project) user_b.profile.save() self.assertNotEqual(user_b.id, user_b.profile.id) self.client.force_authenticate(user=user_a) resp = self.client.patch(self.api_url(patch.id), {'delegate': user_b.id}) self.assertEqual(status.HTTP_200_OK, resp.status_code, resp) self.assertEqual(Patch.objects.get(id=patch.id).state, state) self.assertEqual(Patch.objects.get(id=patch.id).delegate, user_b)
def parse_mail(*args, **kwargs): create_state() return _parse_mail(*args, **kwargs)
def setUp(self): utils.create_state()
def setUp(self): self.project = utils.create_project() utils.create_state()