diff --git a/awx/api/views/__init__.py b/awx/api/views/__init__.py index dd31948acf..9d0e19b95e 100644 --- a/awx/api/views/__init__.py +++ b/awx/api/views/__init__.py @@ -102,7 +102,7 @@ from awx.main.scheduler.dag_workflow import WorkflowDAG from awx.api.views.mixin import ( ControlledByScmMixin, InstanceGroupMembershipMixin, OrganizationCountsMixin, RelatedJobsPreventDeleteMixin, - UnifiedJobDeletionMixin, + UnifiedJobDeletionMixin, NoTruncateMixin, ) from awx.api.views.organization import ( # noqa OrganizationList, @@ -3785,18 +3785,12 @@ class JobHostSummaryDetail(RetrieveAPIView): serializer_class = serializers.JobHostSummarySerializer -class JobEventList(ListAPIView): +class JobEventList(NoTruncateMixin, ListAPIView): model = models.JobEvent serializer_class = serializers.JobEventSerializer search_fields = ('stdout',) - def get_serializer_context(self): - context = super().get_serializer_context() - if self.request.query_params.get('no_truncate'): - context.update(no_truncate=True) - return context - class JobEventDetail(RetrieveAPIView): @@ -3809,7 +3803,7 @@ class JobEventDetail(RetrieveAPIView): return context -class JobEventChildrenList(SubListAPIView): +class JobEventChildrenList(NoTruncateMixin, SubListAPIView): model = models.JobEvent serializer_class = serializers.JobEventSerializer @@ -3834,7 +3828,7 @@ class JobEventHostsList(HostRelatedSearchMixin, SubListAPIView): name = _('Job Event Hosts List') -class BaseJobEventsList(SubListAPIView): +class BaseJobEventsList(NoTruncateMixin, SubListAPIView): model = models.JobEvent serializer_class = serializers.JobEventSerializer @@ -4030,18 +4024,12 @@ class AdHocCommandRelaunch(GenericAPIView): return Response(data, status=status.HTTP_201_CREATED, headers=headers) -class AdHocCommandEventList(ListAPIView): +class AdHocCommandEventList(NoTruncateMixin, ListAPIView): model = models.AdHocCommandEvent serializer_class = serializers.AdHocCommandEventSerializer search_fields = ('stdout',) - def get_serializer_context(self): - context = super().get_serializer_context() - if self.request.query_params.get('no_truncate'): - context.update(no_truncate=True) - return context - class AdHocCommandEventDetail(RetrieveAPIView): @@ -4054,7 +4042,7 @@ class AdHocCommandEventDetail(RetrieveAPIView): return context -class BaseAdHocCommandEventsList(SubListAPIView): +class BaseAdHocCommandEventsList(NoTruncateMixin, SubListAPIView): model = models.AdHocCommandEvent serializer_class = serializers.AdHocCommandEventSerializer diff --git a/awx/api/views/mixin.py b/awx/api/views/mixin.py index 546b7090f2..e7d4959dfc 100644 --- a/awx/api/views/mixin.py +++ b/awx/api/views/mixin.py @@ -270,3 +270,11 @@ class ControlledByScmMixin(object): obj = super(ControlledByScmMixin, self).get_parent_object() self._reset_inv_src_rev(obj) return obj + + +class NoTruncateMixin(object): + def get_serializer_context(self): + context = super().get_serializer_context() + if self.request.query_params.get('no_truncate'): + context.update(no_truncate=True) + return context diff --git a/awx/main/tests/functional/api/test_events.py b/awx/main/tests/functional/api/test_events.py new file mode 100644 index 0000000000..00b5459eaf --- /dev/null +++ b/awx/main/tests/functional/api/test_events.py @@ -0,0 +1,45 @@ +import pytest + +from awx.api.versioning import reverse +from awx.main.models import AdHocCommand, AdHocCommandEvent, JobEvent + + +@pytest.mark.django_db +@pytest.mark.parametrize('truncate, expected', [ + (True, False), + (False, True), +]) +def test_job_events_sublist_truncation(get, organization_factory, job_template_factory, truncate, expected): + objs = organization_factory("org", superusers=['admin']) + jt = job_template_factory("jt", organization=objs.organization, + inventory='test_inv', project='test_proj').job_template + job = jt.create_unified_job() + JobEvent.create_from_data(job_id=job.pk, uuid='abc123', event='runner_on_start', + stdout='a' * 1025) + + url = reverse('api:job_job_events_list', kwargs={'pk': job.pk}) + if not truncate: + url += '?no_truncate=1' + + response = get(url, user=objs.superusers.admin, expect=200) + assert (len(response.data['results'][0]['stdout']) == 1025) == expected + + +@pytest.mark.django_db +@pytest.mark.parametrize('truncate, expected', [ + (True, False), + (False, True), +]) +def test_ad_hoc_events_sublist_truncation(get, organization_factory, job_template_factory, truncate, expected): + objs = organization_factory("org", superusers=['admin']) + adhoc = AdHocCommand() + adhoc.save() + AdHocCommandEvent.create_from_data(ad_hoc_command_id=adhoc.pk, uuid='abc123', event='runner_on_start', + stdout='a' * 1025) + + url = reverse('api:ad_hoc_command_ad_hoc_command_events_list', kwargs={'pk': adhoc.pk}) + if not truncate: + url += '?no_truncate=1' + + response = get(url, user=objs.superusers.admin, expect=200) + assert (len(response.data['results'][0]['stdout']) == 1025) == expected