mirror of
https://github.com/ansible/awx.git
synced 2024-11-01 16:51:11 +03:00
tests and optimizations for UJT list with non-joblet recent_jobs
This commit is contained in:
parent
2a62e300a2
commit
f09b8efa87
@ -2983,13 +2983,16 @@ class JobTemplateMixin(object):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
def _recent_jobs(self, obj):
|
def _recent_jobs(self, obj):
|
||||||
job_mgr = obj.unifiedjob_unified_jobs.non_polymorphic().exclude(job__job_slice_count__gt=1).only(
|
# Exclude "joblets", jobs that ran as part of a sliced workflow job
|
||||||
'id', 'status', 'finished', 'polymorphic_ctype_id')
|
uj_qs = obj.unifiedjob_unified_jobs.exclude(job__job_slice_count__gt=1).order_by('-created')
|
||||||
type_mapping = {}
|
# Would like to apply an .only, but does not play well with non_polymorphic
|
||||||
for model, ct in ContentType.objects.get_for_models(*UnifiedJob.__subclasses__()).iteritems():
|
# .only('id', 'status', 'finished', 'polymorphic_ctype_id')
|
||||||
type_mapping[ct.pk] = model._meta.verbose_name
|
optimized_qs = uj_qs.non_polymorphic()
|
||||||
return [{'id': x.id, 'status': x.status, 'finished': x.finished, 'type': type_mapping[x.polymorphic_ctype_id]}
|
return [{
|
||||||
for x in job_mgr.order_by('-created')[:10]]
|
'id': x.id, 'status': x.status, 'finished': x.finished,
|
||||||
|
# Make type consistent with API top-level key, for instance workflow_job
|
||||||
|
'type': x.get_real_instance_class()._meta.verbose_name.replace(' ', '_')
|
||||||
|
} for x in optimized_qs[:10]]
|
||||||
|
|
||||||
def get_summary_fields(self, obj):
|
def get_summary_fields(self, obj):
|
||||||
d = super(JobTemplateMixin, self).get_summary_fields(obj)
|
d = super(JobTemplateMixin, self).get_summary_fields(obj)
|
||||||
|
@ -1276,6 +1276,7 @@ class JobTemplateAccess(BaseAccess):
|
|||||||
'instance_groups',
|
'instance_groups',
|
||||||
'credentials__credential_type',
|
'credentials__credential_type',
|
||||||
Prefetch('labels', queryset=Label.objects.all().order_by('name')),
|
Prefetch('labels', queryset=Label.objects.all().order_by('name')),
|
||||||
|
Prefetch('last_job', queryset=UnifiedJob.objects.non_polymorphic()),
|
||||||
)
|
)
|
||||||
|
|
||||||
def filtered_queryset(self):
|
def filtered_queryset(self):
|
||||||
|
@ -697,9 +697,9 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self, request=None):
|
def get_absolute_url(self, request=None):
|
||||||
real_instance = self.get_real_instance()
|
RealClass = self.get_real_instance_class()
|
||||||
if real_instance != self:
|
if RealClass != UnifiedJob:
|
||||||
return real_instance.get_absolute_url(request=request)
|
return RealClass.get_absolute_url(RealClass(pk=self.pk), request=request)
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
@ -4,9 +4,11 @@ import mock
|
|||||||
from dateutil.parser import parse
|
from dateutil.parser import parse
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from crum import impersonate
|
from crum import impersonate
|
||||||
|
import datetime
|
||||||
|
|
||||||
# Django rest framework
|
# Django rest framework
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.api.versioning import reverse
|
from awx.api.versioning import reverse
|
||||||
@ -122,6 +124,31 @@ def test_job_relaunch_on_failed_hosts(post, inventory, project, machine_credenti
|
|||||||
assert r.data.get('limit') == hosts
|
assert r.data.get('limit') == hosts
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_summary_fields_recent_jobs(job_template, admin_user, get):
|
||||||
|
jobs = []
|
||||||
|
for i in range(13):
|
||||||
|
jobs.append(Job.objects.create(
|
||||||
|
job_template=job_template,
|
||||||
|
status='failed',
|
||||||
|
created=timezone.make_aware(datetime.datetime(2017, 3, 21, 9, i)),
|
||||||
|
finished=timezone.make_aware(datetime.datetime(2017, 3, 21, 10, i))
|
||||||
|
))
|
||||||
|
r = get(
|
||||||
|
url = job_template.get_absolute_url(),
|
||||||
|
user = admin_user,
|
||||||
|
exepect = 200
|
||||||
|
)
|
||||||
|
recent_jobs = r.data['summary_fields']['recent_jobs']
|
||||||
|
assert len(recent_jobs) == 10
|
||||||
|
assert recent_jobs == [{
|
||||||
|
'id': job.id,
|
||||||
|
'status': 'failed',
|
||||||
|
'finished': job.finished,
|
||||||
|
'type': 'job'
|
||||||
|
} for job in jobs[-10:][::-1]]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_slice_jt_recent_jobs(slice_job_factory, admin_user, get):
|
def test_slice_jt_recent_jobs(slice_job_factory, admin_user, get):
|
||||||
workflow_job = slice_job_factory(3, spawn=True)
|
workflow_job = slice_job_factory(3, spawn=True)
|
||||||
@ -132,10 +159,9 @@ def test_slice_jt_recent_jobs(slice_job_factory, admin_user, get):
|
|||||||
expect=200
|
expect=200
|
||||||
)
|
)
|
||||||
job_ids = [entry['id'] for entry in r.data['summary_fields']['recent_jobs']]
|
job_ids = [entry['id'] for entry in r.data['summary_fields']['recent_jobs']]
|
||||||
assert workflow_job.pk not in job_ids
|
# decision is that workflow job should be shown in the related jobs
|
||||||
for node in workflow_job.workflow_nodes.all():
|
# joblets of the workflow job should NOT be shown
|
||||||
job = node.job
|
assert job_ids == [workflow_job.pk]
|
||||||
assert job.pk in job_ids
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
@ -69,35 +69,17 @@ class TestJobTemplateSerializerGetRelated():
|
|||||||
|
|
||||||
|
|
||||||
class TestJobTemplateSerializerGetSummaryFields():
|
class TestJobTemplateSerializerGetSummaryFields():
|
||||||
def test__recent_jobs(self, mocker, job_template, jobs):
|
|
||||||
|
|
||||||
job_template.unifiedjob_unified_jobs = mocker.MagicMock(**{
|
|
||||||
'non_polymorphic.return_value': mocker.MagicMock(**{
|
|
||||||
'only.return_value': mocker.MagicMock(**{
|
|
||||||
'order_by.return_value': jobs
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
serializer = JobTemplateSerializer()
|
|
||||||
recent_jobs = serializer._recent_jobs(job_template)
|
|
||||||
|
|
||||||
job_template.unifiedjob_unified_jobs.non_polymorphic.assert_called_once_with()
|
|
||||||
job_template.unifiedjob_unified_jobs.non_polymorphic().only().order_by.assert_called_once_with('-created')
|
|
||||||
|
|
||||||
job_template.jobs.all.assert_called_once_with()
|
|
||||||
job_template.jobs.all.order_by.assert_called_once_with('-created')
|
|
||||||
assert len(recent_jobs) == 10
|
|
||||||
for x in jobs[:10]:
|
|
||||||
assert recent_jobs == [{'id': x.id, 'status': x.status, 'finished': x.finished} for x in jobs[:10]]
|
|
||||||
|
|
||||||
def test_survey_spec_exists(self, test_get_summary_fields, mocker, job_template):
|
def test_survey_spec_exists(self, test_get_summary_fields, mocker, job_template):
|
||||||
job_template.survey_spec = {'name': 'blah', 'description': 'blah blah'}
|
job_template.survey_spec = {'name': 'blah', 'description': 'blah blah'}
|
||||||
test_get_summary_fields(JobTemplateSerializer, job_template, 'survey')
|
with mocker.patch.object(JobTemplateSerializer, '_recent_jobs') as mock_rj:
|
||||||
|
mock_rj.return_value = []
|
||||||
|
test_get_summary_fields(JobTemplateSerializer, job_template, 'survey')
|
||||||
|
|
||||||
def test_survey_spec_absent(self, get_summary_fields_mock_and_run, job_template):
|
def test_survey_spec_absent(self, get_summary_fields_mock_and_run, mocker, job_template):
|
||||||
job_template.survey_spec = None
|
job_template.survey_spec = None
|
||||||
summary = get_summary_fields_mock_and_run(JobTemplateSerializer, job_template)
|
with mocker.patch.object(JobTemplateSerializer, '_recent_jobs') as mock_rj:
|
||||||
|
mock_rj.return_value = []
|
||||||
|
summary = get_summary_fields_mock_and_run(JobTemplateSerializer, job_template)
|
||||||
assert 'survey' not in summary
|
assert 'survey' not in summary
|
||||||
|
|
||||||
def test_copy_edit_standard(self, mocker, job_template_factory):
|
def test_copy_edit_standard(self, mocker, job_template_factory):
|
||||||
|
@ -26,7 +26,7 @@ export default ['$scope', '$filter', 'i18n',
|
|||||||
const finished = $filter('longDate')(job.finished) || job.status+"";
|
const finished = $filter('longDate')(job.finished) || job.status+"";
|
||||||
|
|
||||||
// We now get the job type of recent jobs associated with a JT
|
// We now get the job type of recent jobs associated with a JT
|
||||||
if (job.type === 'workflow job') {
|
if (job.type === 'workflow_job') {
|
||||||
detailsBaseUrl = '/#/workflows/';
|
detailsBaseUrl = '/#/workflows/';
|
||||||
} else if (job.type === 'job') {
|
} else if (job.type === 'job') {
|
||||||
detailsBaseUrl = '/#/jobs/playbook/';
|
detailsBaseUrl = '/#/jobs/playbook/';
|
||||||
|
Loading…
Reference in New Issue
Block a user