def test_utf8_nbsp_tags(self): """Test that UTF-8 NBSP characters are correctly handled.""" patch = create_patch(content='patch text\n') create_patch_comment(patch=patch, content=u'comment\nAcked-by:\u00A0 foo') mbox = utils.patch_to_mbox(patch) self.assertIn(u'\u00A0 foo\n', mbox)
def test_tags(self): """Test that tags are taken from a patch comment.""" patch = create_patch(content='comment 1 text\nAcked-by: 1\n') create_patch_comment(patch=patch, content='comment 2 text\nAcked-by: 2\n') mbox = utils.patch_to_mbox(patch) self.assertIn('Acked-by: 1\nAcked-by: 2\n', mbox)
def test_multiple_content_types(self): """Test what happens when a patch and comment have different Content-Type headers.""" _, patches, _ = self._parse_mbox('bugs-multiple-content-types.mbox', [0, 1, 1]) patch = patches[0] self.assertEqual(patch_to_mbox(patch).count('Content-Type:'), 1)
def test_date_header(self): patch = create_patch() mbox = utils.patch_to_mbox(patch) mail = email.message_from_string(mbox) 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_patchwork_submitter_header(self): """Validate inclusion of generated 'X-Patchwork-Submitter' header.""" email = '*****@*****.**' from_header = f'From: Jon Doe <{email}>\n' person = create_person(name='Jonathon Doe', email=email) submitter_header = f'X-Patchwork-Submitter: {person.name} <{email}>' patch = create_patch(submitter=person, headers=from_header) mbox = utils.patch_to_mbox(patch) self.assertIn(from_header, mbox) self.assertIn(submitter_header, mbox)
def test_from_header(self): """Validate non-ascii 'From' header. Test that a person with characters outside ASCII in his name do produce correct From header. As RFC 2822 state we must retain the <*****@*****.**> format for the mail while the name part may be coded in some ways. """ person = create_person(name=u'©ool guŷ') patch = create_patch(submitter=person) from_email = f'<{person.email}>' mbox = utils.patch_to_mbox(patch) self.assertIn(from_email, mbox)
def patch_mbox(request, patch_id): patch = get_object_or_404(Patch, id=patch_id) series_id = request.GET.get('series') response = HttpResponse(content_type='text/plain') if series_id: response.write(series_patch_to_mbox(patch, series_id)) else: response.write(patch_to_mbox(patch)) response['Content-Disposition'] = 'attachment; filename=%s.patch' % ( patch.filename) return response
def patch_mbox(request, patch_id): patch = get_object_or_404(Patch, id=patch_id) series_id = request.GET.get('series') response = HttpResponse(content_type='text/plain') if series_id: response.write(series_patch_to_mbox(patch, series_id)) else: response.write(patch_to_mbox(patch)) response['Content-Disposition'] = 'attachment; filename=' + \ patch.filename.replace(';', '').replace('\n', '') return response
def test_supplied_date_header(self): patch = create_patch() offset = 3 * 60 * 60 # 3 (hours) * 60 (minutes) * 60 (seconds) tz = dateutil.tz.tzoffset(None, offset) date = datetime.datetime.utcnow() - datetime.timedelta(days=1) date = date.replace(tzinfo=tz, microsecond=0) patch.headers = 'Date: %s\n' % date.strftime("%a, %d %b %Y %T %z") patch.save() mbox = utils.patch_to_mbox(patch) mail = email.message_from_string(mbox) mail_date = dateutil.parser.parse(mail['Date']) self.assertEqual(mail_date, date)
def patch_mbox(request, project_id, msgid): db_msgid = ('<%s>' % msgid) project = get_object_or_404(Project, linkname=project_id) patch = get_object_or_404(Patch, project_id=project.id, msgid=db_msgid) series_id = request.GET.get('series') response = HttpResponse(content_type='text/plain; charset=utf-8') if series_id: response.write(series_patch_to_mbox(patch, series_id)) else: response.write(patch_to_mbox(patch)) response['Content-Disposition'] = 'attachment; filename=%s.patch' % ( patch.filename) return response
def test_comment_unchanged(self): """Validate postscript part of mail is unchanged. Test that the mbox view doesn't change the postscript part of a mail. There where always a missing blank right after the postscript delimiter '---' and an additional newline right before. """ content = 'some comment\n---\n some/file | 1 +\n' project = create_project() patch = create_patch(content=content, diff='', project=project) mbox = utils.patch_to_mbox(patch) self.assertIn(content, mbox) self.assertNotIn(content + '\n', mbox)
def test_dmarc_from_header(self): """Validate 'From' header is rewritten correctly when DMARC-munged. Test that when an email with a DMARC-munged From header is processed, the From header will be unmunged and the munged address will be saved as 'X-Patchwork-Original-From'. """ orig_from_header = 'Person via List <*****@*****.**>' rewritten_from_header = 'Person <*****@*****.**>' project = create_project(listemail='*****@*****.**') person = create_person(name='Person', email='*****@*****.**') patch = create_patch(project=project, headers='From: ' + orig_from_header, submitter=person) mbox = utils.patch_to_mbox(patch) mail = email.message_from_string(mbox) self.assertEqual(mail['From'], rewritten_from_header) self.assertEqual(mail['X-Patchwork-Original-From'], orig_from_header)
def patch_get_mbox(patch_id): """Get a patch by its ID in mbox format. Retrieve a patch matching a given patch ID, if any exists, and return in mbox format. Args: patch_id (int): The ID of the patch to retrieve. Returns: The serialized patch matching the ID, if any, in mbox format, else an empty string. """ try: patch = Patch.objects.get(id=patch_id) return patch_to_mbox(patch) except Patch.DoesNotExist: return ''
def patch_mbox(request, patch_id): patch = get_object_or_404(Patch, id=patch_id) series_id = request.GET.get('series') response = HttpResponse(content_type='text/plain') if series_id: if not patch.series: raise Http404('Patch does not have an associated series. This is ' 'because the patch was processed with an older ' 'version of Patchwork. It is not possible to ' 'provide dependencies for this patch.') response.write(series_patch_to_mbox(patch, series_id)) else: response.write(patch_to_mbox(patch)) response['Content-Disposition'] = 'attachment; filename=%s.patch' % ( patch.filename) return response
def test_multiple_tags(self): """Test that the mbox view appends tags correct. Ensure the tags are extracted from a patch comment, and placed before an '---' update line. """ self.project = create_project() self.person = create_person() self.patch = create_patch( project=self.project, submitter=self.person, diff='', content='comment 1 text\nAcked-by: 1\n---\nupdate\n') self.comment = create_patch_comment( patch=self.patch, submitter=self.person, content='comment 2 text\nAcked-by: 2\n') mbox = utils.patch_to_mbox(self.patch) self.assertIn('Acked-by: 1\nAcked-by: 2\n', mbox)
def handle(self, *args, **options): if options['projects']: projects = [] for listid in options['projects']: try: projects.append(Project.objects.get(listid=listid)) except Project.DoesNotExist: raise CommandError('Project not found: %s' % listid) else: projects = list(Project.objects.all()) name = 'patchwork_dump_' + datetime.now().strftime('%Y_%m_%d_%H%M%S') if options['compress']: name += '.tar.gz' compress_level = 9 else: name += '.tar' compress_level = 1 self.stdout.write('Generating patch archive...') with tarfile.open(name, 'w:gz', compresslevel=compress_level) as tar: for i, project in enumerate(projects): self.stdout.write('Project %02d/%02d (%s)' % (i + 1, len(projects), project.linkname)) with tempfile.NamedTemporaryFile(delete=False) as mbox: patches = Patch.objects.filter(project=project) count = patches.count() for j, patch in enumerate(patches): if not (j % 10): self.stdout.write('%06d/%06d\r' % (j, count), ending='') self.stdout.flush() mbox.write(force_bytes(patch_to_mbox(patch) + '\n')) tar.add(mbox.name, arcname='%s.mbox' % project.linkname) self.stdout.write('Dumped patch archive to %r' % name)
def test_patchwork_id_header(self): """Validate inclusion of generated 'X-Patchwork-Id' header.""" patch = create_patch() mbox = utils.patch_to_mbox(patch) self.assertIn('X-Patchwork-Id: %d' % patch.id, mbox)
def test_patchwork_delegate_header(self): """Validate inclusion of generated 'X-Patchwork-Delegate' header.""" user = create_user() patch = create_patch(delegate=user) mbox = utils.patch_to_mbox(patch) self.assertIn('X-Patchwork-Delegate: %s' % user.email, mbox)
def _test_header_dropped(self, header): patch = create_patch(headers=header + '\n') mbox = utils.patch_to_mbox(patch) self.assertNotIn(header, mbox)
def _test_header_passthrough(self, header): patch = create_patch(headers=header + '\n') mbox = utils.patch_to_mbox(patch) self.assertIn(header, mbox)