diff --git a/awx/api/views.py b/awx/api/views.py index 20a6681d36..fdce0b9f3b 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -282,10 +282,16 @@ class DashboardView(APIView): user_hosts = get_user_queryset(request.user, Host) user_hosts_failed = user_hosts.filter(has_active_failures=True) + try: + user_hosts_count = user_hosts.distinct('name').count() + user_hosts_failed_count = user_hosts_failed.distinct('name').count() + except NotImplementedError: # For unit tests only, SQLite doesn't support distinct('name') + user_hosts_count = len(set(user_hosts.values_list('name', flat=True))) + user_hosts_failed_count = len(set(user_hosts_failed.values_list('name', flat=True))) data['hosts'] = {'url': reverse('api:host_list'), 'failures_url': reverse('api:host_list') + "?has_active_failures=True", - 'total': user_hosts.count(), - 'failed': user_hosts_failed.count()} + 'total': user_hosts_count, + 'failed': user_hosts_failed_count} user_projects = get_user_queryset(request.user, Project) user_projects_failed = user_projects.filter(last_job_failed=True) diff --git a/awx/main/tests/inventory.py b/awx/main/tests/inventory.py index 62741c1678..8771501062 100644 --- a/awx/main/tests/inventory.py +++ b/awx/main/tests/inventory.py @@ -1089,6 +1089,45 @@ class InventoryTest(BaseTest): self.assertEqual(set(h_e.all_groups.values_list('pk', flat=True)), set([g_e.pk])) + def test_dashboard_hosts_count(self): + url = reverse('api:dashboard_view') + + # Test with zero hosts. + with self.current_user(self.super_django_user): + response = self.get(url, expect=200) + self.assertEqual(response['hosts']['total'], 0) + self.assertEqual(response['hosts']['failed'], 0) + + # Create hosts with the same name in different inventories. + for x in xrange(4): + hostname = 'host-%d' % x + self.inventory_a.hosts.create(name=hostname) + self.inventory_b.hosts.create(name=hostname) + with self.current_user(self.super_django_user): + response = self.get(url, expect=200) + self.assertEqual(response['hosts']['total'], 4) + self.assertEqual(response['hosts']['failed'], 0) + + # Mark all hosts in one inventory as failed. Failed count should + # reflect unique hostnames. + for host in self.inventory_a.hosts.all(): + host.has_active_failures = True + host.save() + with self.current_user(self.super_django_user): + response = self.get(url, expect=200) + self.assertEqual(response['hosts']['total'], 4) + self.assertEqual(response['hosts']['failed'], 4) + + # Mark all hosts in the other inventory as failed. Failed count + # should reflect unique hostnames and never be greater than total. + for host in self.inventory_b.hosts.all(): + host.has_active_failures = True + host.save() + with self.current_user(self.super_django_user): + response = self.get(url, expect=200) + self.assertEqual(response['hosts']['total'], 4) + self.assertEqual(response['hosts']['failed'], 4) + def test_dashboard_inventory_graph_view(self): url = reverse('api:dashboard_inventory_graph_view') # Test with zero hosts.