def test_patch_dependencies_out_of_order(self): series = utils.create_series() patch_3 = utils.create_patch(series=series, number=3) patch_2 = utils.create_patch(series=series, number=2) # This should only raise the CATEGORY_PATCH_CREATED event for # both patches as they are both missing dependencies for patch in [patch_2, patch_3]: events = _get_events(patch=patch) self.assertEqual(events.count(), 1) self.assertEqual(events[0].category, Event.CATEGORY_PATCH_CREATED) self.assertEventFields(events[0]) patch_1 = utils.create_patch(series=series, number=1) # We should now see the CATEGORY_PATCH_COMPLETED event for all patches # as the dependencies for all have been met for patch in [patch_1, patch_2, patch_3]: events = _get_events(patch=patch) self.assertEqual(events.count(), 2) self.assertEqual(events[0].category, Event.CATEGORY_PATCH_CREATED) self.assertEqual(events[1].category, Event.CATEGORY_PATCH_COMPLETED) self.assertEventFields(events[0]) self.assertEventFields(events[1])
def setUp(self): self.project = create_project() for name, email, date in self.patchmeta: person = create_person(name=name, email=email) create_patch(submitter=person, project=self.project, date=date)
def _create_series(self): project_obj = create_project(linkname='myproject') person_obj = create_person(email='*****@*****.**') series_obj = create_series(project=project_obj, submitter=person_obj) create_cover(series=series_obj) create_patch(series=series_obj) return series_obj
def test_list_version_1_0(self): create_patch() resp = self.client.get(self.api_url(version='1.0')) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) self.assertIn('url', resp.data[0]) self.assertNotIn('web_url', resp.data[0])
def test_series(self): series = create_series() patch_a = create_patch(series=series) patch_b = create_patch(series=series) response = self.client.get(reverse('series-mbox', args=[series.id])) self.assertContains(response, patch_a.content) self.assertContains(response, patch_b.content)
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_detail_version_1_0(self): patch = create_patch() resp = self.client.get(self.api_url(item=patch.id, version='1.0')) self.assertIn('url', resp.data) self.assertNotIn('web_url', resp.data) self.assertNotIn('comments', resp.data)
def test_anonymous_delete(self): """Ensure anonymous "DELETE" operations are rejected.""" patch = create_patch() patch_url = self.api_url(patch.id) resp = self.client.delete(patch_url) self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
def test_patch_submitter_expiry(self): # someone submits a patch... patch = create_patch() submitter = patch.submitter # ... then starts registration... date = ((datetime.datetime.utcnow() - EmailConfirmation.validity) - datetime.timedelta(hours=1)) user = create_user(link_person=False, email=submitter.email) user.is_active = False user.date_joined = user.last_login = date user.save() conf = EmailConfirmation(type='registration', user=user, email=user.email) conf.date = date conf.save() # ... which expires expire_notifications() # we should see no matching user self.assertFalse(User.objects.filter(email=patch.submitter.email) .exists()) # but the patch and person should still be present self.assertTrue(Person.objects.filter(pk=submitter.pk).exists()) self.assertTrue(Patch.objects.filter(pk=patch.pk).exists()) # and there should be no user associated with the person self.assertEqual(Person.objects.get(pk=submitter.pk).user, None)
def setUp(self): super(TestCheckAPI, self).setUp() project = create_project() self.user = create_maintainer(project) self.patch = create_patch(project=project) self.urlbase = reverse('api_1.0:patch-detail', args=[self.patch.id]) self.urlbase += 'checks/'
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_list_version_1_0(self): """List patch comments using API v1.0.""" patch = create_patch() create_comment(submission=patch) # check we can't access comments using the old version of the API with self.assertRaises(NoReverseMatch): self.client.get(self.api_url(patch, version='1.0'))
def test_redirect(self): patch_id = create_patch().id requested_url = reverse('cover-detail', kwargs={'cover_id': patch_id}) redirect_url = reverse('patch-detail', kwargs={'patch_id': patch_id}) response = self.client.get(requested_url) self.assertRedirects(response, redirect_url)
def test_no_ready_notifications(self): """We shouldn't see immediate notifications.""" patch = create_patch(project=self.project) PatchChangeNotification(patch=patch, orig_state=patch.state).save() errors = send_notifications() self.assertEqual(errors, []) self.assertEqual(len(mail.outbox), 0)
def test_detail_tags(self): patch = create_patch( content='Reviewed-by: Test User <*****@*****.**>\n') resp = self.client.get(self.api_url(patch.id)) tags = resp.data['tags'] self.assertEqual(1, len(tags)) self.assertEqual(1, tags[0]['count']) self.assertEqual('Reviewed-by', tags[0]['name'])
def test_patch_uninteresting_change(self): """Ensure we don't get a notification for "uninteresting" changes""" patch = create_patch(project=self.project) patch.archived = True patch.save() self.assertEqual(PatchChangeNotification.objects.count(), 0)
def test_date_header(self): patch = create_patch() response = self.client.get(reverse('patch-mbox', args=[patch.id])) mail = email.message_from_string(response.content.decode()) mail_date = dateutil.parser.parse(mail['Date']) # patch dates are all in UTC patch_date = patch.date.replace(tzinfo=dateutil.tz.tzutc(), microsecond=0) self.assertEqual(mail_date, patch_date)
def test_list(self): """List checks.""" check_obj = self._create_check() self._create_check(create_patch()) # second, unrelated patch resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) self.assertSerialized(check_obj, resp.data[0])
def test_legacy_patch(self): """Validate a patch with non-existent dependencies raises a 404.""" # we're explicitly creating a patch without a series patch = create_patch() response = self.client.get('%s?series=*' % reverse( 'patch-mbox', args=[patch.id])) self.assertEqual(response.status_code, 404)
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_list(self): """List patch comments.""" patch = create_patch() comment = create_comment(submission=patch) resp = self.client.get(self.api_url(patch)) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) self.assertSerialized(comment, resp.data[0])
def test_list(self): """Validate we can list series.""" resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(0, len(resp.data)) project_obj = create_project(linkname='myproject') person_obj = create_person(email='*****@*****.**') series_obj = create_series(project=project_obj, submitter=person_obj) create_cover(series=series_obj) create_patch(series=series_obj) # anonymous users resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) series_rsp = resp.data[0] self.assertSerialized(series_obj, series_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)) series_rsp = resp.data[0] self.assertSerialized(series_obj, series_rsp) # test filtering by project resp = self.client.get(self.api_url(), {'project': 'myproject'}) self.assertEqual([series_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 owner, both ID and email resp = self.client.get(self.api_url(), {'submitter': person_obj.id}) self.assertEqual([series_obj.id], [x['id'] for x in resp.data]) resp = self.client.get(self.api_url(), { 'submitter': '*****@*****.**'}) self.assertEqual([series_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_dependencies_missing(self): series = utils.create_series() patch = utils.create_patch(series=series, number=2) # This should only raise the CATEGORY_PATCH_CREATED event as # there is a missing dependency (patch 1) events = _get_events(patch=patch) self.assertEqual(events.count(), 1) self.assertEqual(events[0].category, Event.CATEGORY_PATCH_CREATED) self.assertEventFields(events[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_patch_set(self): patch = utils.create_patch(project=self.project) result = self.rpc.patch_get(patch.id) self.assertFalse(result['archived']) self.rpc.patch_set(patch.id, {'archived': True}) # reload the patch result = self.rpc.patch_get(patch.id) self.assertTrue(result['archived'])
def test_patchwork_from_header(self): """Validate inclusion of generated 'X-Patchwork-From' header.""" email = '*****@*****.**' from_header = 'From: Jon Doe <%s>\n' % email person = create_person(name='Jonathon Doe', email=email) patch = create_patch(submitter=person, headers=from_header) response = self.client.get(reverse('patch-mbox', args=[patch.id])) self.assertContains(response, from_header) self.assertContains(response, 'X-Patchwork-Submitter: %s <%s>' % ( person.name, email))
def test_patch_created(self): """No series, so patch dependencies implicitly exist.""" patch = utils.create_patch() # This should raise both the CATEGORY_PATCH_CREATED and # CATEGORY_PATCH_COMPLETED events as there are no specific dependencies events = _get_events(patch=patch) self.assertEqual(events.count(), 1) self.assertEqual(events[0].category, Event.CATEGORY_PATCH_CREATED) self.assertEqual(events[0].project, patch.project) self.assertEventFields(events[0])
def test_patch_utf8_nbsp(self): patch = create_patch( project=self.project, submitter=self.person, content='patch text\n') create_comment( submission=patch, submitter=self.person, content=u'comment\nAcked-by:\u00A0 foo') response = self.client.get(reverse('patch-mbox', args=[patch.id])) self.assertContains(response, u'\u00A0 foo\n')
def test_patch_response(self): patch = create_patch( project=self.project, submitter=self.person, content='comment 1 text\nAcked-by: 1\n') create_comment( submission=patch, submitter=self.person, content='comment 2 text\nAcked-by: 2\n') response = self.client.get(reverse('patch-mbox', args=[patch.id])) self.assertContains(response, 'Acked-by: 1\nAcked-by: 2\n')
def test_patchwork_id_header(self): """Validate inclusion of generated 'X-Patchwork-Id' header.""" patch = create_patch() response = self.client.get(reverse('patch-mbox', args=[patch.id])) self.assertContains(response, 'X-Patchwork-Id: %d' % patch.id)
def _test_header_passthrough(self, header): patch = create_patch(headers=header + '\n') response = self.client.get(reverse('patch-mbox', args=[patch.id])) self.assertContains(response, header)
def test_patchwork_delegate_header(self): """Validate inclusion of generated 'X-Patchwork-Delegate' header.""" user = create_user() patch = create_patch(delegate=user) response = self.client.get(reverse('patch-mbox', args=[patch.id])) self.assertContains(response, 'X-Patchwork-Delegate: %s' % user.email)