diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index c5bf753067..1910c096ee 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -33,7 +33,7 @@ from awx.main.models.notifications import ( NotificationTemplate, JobNotificationMixin, ) -from awx.main.utils import parse_yaml_or_json +from awx.main.utils import parse_yaml_or_json, getattr_dne from awx.main.fields import ImplicitRoleField from awx.main.models.mixins import ( ResourceMixin, @@ -1038,7 +1038,8 @@ class JobHostSummary(CreatedModifiedModel): failed = models.BooleanField(default=False, editable=False) def __unicode__(self): - hostname = self.host.name if self.host else 'N/A' + host = getattr_dne(self, 'host') + hostname = host.name if host else 'N/A' return '%s changed=%d dark=%d failures=%d ok=%d processed=%d skipped=%s' % \ (hostname, self.changed, self.dark, self.failures, self.ok, self.processed, self.skipped) diff --git a/awx/main/tests/functional/models/test_job.py b/awx/main/tests/functional/models/test_job.py index ec23045fea..013f73ca39 100644 --- a/awx/main/tests/functional/models/test_job.py +++ b/awx/main/tests/functional/models/test_job.py @@ -1,6 +1,7 @@ import pytest +import six -from awx.main.models import JobTemplate, Job +from awx.main.models import JobTemplate, Job, JobHostSummary from crum import impersonate @@ -65,3 +66,18 @@ def test_update_parent_instance(job_template, alice): assert job_template.current_job == job assert job_template.status == 'pending' assert job_template.modified_by is None + + +@pytest.mark.django_db +def test_job_host_summary_representation(host): + job = Job.objects.create(name='foo') + jhs = JobHostSummary.objects.create( + host=host, job=job, + changed=1, dark=2, failures=3, ok=4, processed=5, skipped=6 + ) + assert 'single-host changed=1 dark=2 failures=3 ok=4 processed=5 skipped=6' == six.text_type(jhs) + + # Representation should be robust to deleted related items + jhs = JobHostSummary.objects.get(pk=jhs.id) + host.delete() + assert 'N/A changed=1 dark=2 failures=3 ok=4 processed=5 skipped=6' == six.text_type(jhs)