properly compose stdout downloads that contain unicode

This commit is contained in:
Ryan Petrello
2018-01-09 23:45:30 -05:00
parent c0a641ed52
commit 4bb2b5768e
2 changed files with 28 additions and 5 deletions

View File

@@ -2,7 +2,7 @@
# All Rights Reserved. # All Rights Reserved.
# Python # Python
from cStringIO import StringIO from StringIO import StringIO
import json import json
import logging import logging
import os import os
@@ -1013,7 +1013,7 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
return content return content
def _result_stdout_raw(self, redact_sensitive=False, escape_ascii=False): def _result_stdout_raw(self, redact_sensitive=False, escape_ascii=False):
content = self.result_stdout_raw_handle().read() content = self.result_stdout_raw_handle().read().decode('utf-8')
if redact_sensitive: if redact_sensitive:
content = UriCleaner.remove_sensitive(content) content = UriCleaner.remove_sensitive(content)
if escape_ascii: if escape_ascii:
@@ -1029,13 +1029,13 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
return self._result_stdout_raw(escape_ascii=True) return self._result_stdout_raw(escape_ascii=True)
def _result_stdout_raw_limited(self, start_line=0, end_line=None, redact_sensitive=True, escape_ascii=False): def _result_stdout_raw_limited(self, start_line=0, end_line=None, redact_sensitive=True, escape_ascii=False):
return_buffer = u"" return_buffer = StringIO()
if end_line is not None: if end_line is not None:
end_line = int(end_line) end_line = int(end_line)
stdout_lines = self.result_stdout_raw_handle().readlines() stdout_lines = self.result_stdout_raw_handle().readlines()
absolute_end = len(stdout_lines) absolute_end = len(stdout_lines)
for line in stdout_lines[int(start_line):end_line]: for line in stdout_lines[int(start_line):end_line]:
return_buffer += line return_buffer.write(line)
if int(start_line) < 0: if int(start_line) < 0:
start_actual = len(stdout_lines) + int(start_line) start_actual = len(stdout_lines) + int(start_line)
end_actual = len(stdout_lines) end_actual = len(stdout_lines)
@@ -1046,6 +1046,7 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
else: else:
end_actual = len(stdout_lines) end_actual = len(stdout_lines)
return_buffer = return_buffer.getvalue().decode('utf-8')
if redact_sensitive: if redact_sensitive:
return_buffer = UriCleaner.remove_sensitive(return_buffer) return_buffer = UriCleaner.remove_sensitive(return_buffer)
if escape_ascii: if escape_ascii:

View File

@@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
import re import re
import shutil import shutil
import tempfile import tempfile
@@ -40,7 +42,7 @@ def sqlite_copy_expert(request):
InventoryUpdateEvent, SystemJobEvent): InventoryUpdateEvent, SystemJobEvent):
if cls._meta.db_table == tablename: if cls._meta.db_table == tablename:
for event in cls.objects.order_by('start_line').all(): for event in cls.objects.order_by('start_line').all():
fd.write(event.stdout) fd.write(event.stdout.encode('utf-8'))
setattr(SQLiteCursorWrapper, 'copy_expert', write_stdout) setattr(SQLiteCursorWrapper, 'copy_expert', write_stdout)
request.addfinalizer(lambda: shutil.rmtree(path)) request.addfinalizer(lambda: shutil.rmtree(path))
@@ -229,3 +231,23 @@ def test_legacy_result_stdout_with_max_bytes(Cls, view, fmt, get, admin):
response = get(url + '?format={}'.format(fmt + '_download'), user=admin, expect=200) response = get(url + '?format={}'.format(fmt + '_download'), user=admin, expect=200)
assert response.content == large_stdout assert response.content == large_stdout
@pytest.mark.django_db
@pytest.mark.parametrize('Parent, Child, relation, view', [
[Job, JobEvent, 'job', 'api:job_stdout'],
[AdHocCommand, AdHocCommandEvent, 'ad_hoc_command', 'api:ad_hoc_command_stdout'],
[_mk_project_update, ProjectUpdateEvent, 'project_update', 'api:project_update_stdout'],
[_mk_inventory_update, InventoryUpdateEvent, 'inventory_update', 'api:inventory_update_stdout'],
])
@pytest.mark.parametrize('fmt', ['txt', 'ansi', 'txt_download', 'ansi_download'])
def test_text_with_unicode_stdout(sqlite_copy_expert, Parent, Child, relation,
view, get, admin, fmt):
job = Parent()
job.save()
for i in range(3):
Child(**{relation: job, 'stdout': u'{}\n'.format(i), 'start_line': i}).save()
url = reverse(view, kwargs={'pk': job.pk}) + '?format=' + fmt
response = get(url, user=admin, expect=200)
assert response.content.splitlines() == ['%d' % i for i in range(3)]