Merge ~adam-collard/maas:2.8-fix-1884112-count-aggregates into maas:2.8

Proposed by Adam Collard
Status: Merged
Approved by: Adam Collard
Approved revision: 6dcf306ef33e3907353f17757912d8ba8855d3b5
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~adam-collard/maas:2.8-fix-1884112-count-aggregates
Merge into: maas:2.8
Diff against target: 80 lines (+24/-5)
2 files modified
src/maasserver/websockets/handlers/tests/test_user.py (+21/-3)
src/maasserver/websockets/handlers/user.py (+3/-2)
Reviewer Review Type Date Requested Status
Adam Collard (community) Approve
Review via email: mp+386348@code.launchpad.net

Commit message

[2.8 backport] Use distinct=True to avoid Django gotcha with multiple aggregations

Fixes LP:1884112, work around https://code.djangoproject.com/ticket/10060

To post a comment you must log in.
Revision history for this message
Adam Collard (adam-collard) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/websockets/handlers/tests/test_user.py b/src/maasserver/websockets/handlers/tests/test_user.py
2index 2eaecaa..f62c79c 100644
3--- a/src/maasserver/websockets/handlers/tests/test_user.py
4+++ b/src/maasserver/websockets/handlers/tests/test_user.py
5@@ -1,4 +1,4 @@
6-# Copyright 2015-2018 Canonical Ltd. This software is licensed under the
7+# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
8 # GNU Affero General Public License version 3 (see the file LICENSE).
9
10 """Tests for `maasserver.websockets.handlers.user`"""
11@@ -10,6 +10,7 @@ import datetime
12 from django.contrib.auth.models import User
13 from testtools.testcase import TestCase
14
15+from maasserver.enum import NODE_STATUS
16 from maasserver.models.event import Event
17 from maasserver.models.user import SYSTEM_USERS
18 from maasserver.permissions import (
19@@ -64,15 +65,17 @@ class TestUserHandler(MAASServerTestCase):
20 # testtools' assertRaises predates unittest's which has
21 # support for context-manager
22 self.assertRaises = super(TestCase, self).assertRaises
23+ # likewise assertEqual in unittest has gotten much better
24+ self.assertEqual = super(TestCase, self).assertEqual
25
26- def dehydrate_user(self, user, sshkeys_count=0, for_self=False):
27+ def dehydrate_user(self, user, for_self=False):
28 data = {
29 "id": user.id,
30 "username": user.username,
31 "last_name": user.last_name,
32 "email": user.email,
33 "is_superuser": user.is_superuser,
34- "sshkeys_count": sshkeys_count,
35+ "sshkeys_count": user.sshkey_set.count(),
36 "last_login": dehydrate_datetime(user.last_login),
37 "is_local": user.userprofile.is_local,
38 "completed_intro": user.userprofile.completed_intro,
39@@ -163,6 +166,21 @@ class TestUserHandler(MAASServerTestCase):
40 [self.dehydrate_user(user, for_self=True)], handler.list({})
41 )
42
43+ def test_list_with_sshkeys_and_machines(self):
44+ user, keys = factory.make_user_with_keys()
45+ num_machines = 3
46+ for _ in range(num_machines):
47+ node = factory.make_Node(status=NODE_STATUS.READY)
48+ node.acquire(user)
49+ handler = UserHandler(user, {}, None)
50+ users_from_ws = handler.list({})
51+ self.assertEqual(
52+ [self.dehydrate_user(user, for_self=True)], users_from_ws
53+ )
54+ user_from_ws = users_from_ws[0]
55+ self.assertEqual(user_from_ws["sshkeys_count"], len(keys))
56+ self.assertEqual(user_from_ws["machines_count"], num_machines)
57+
58 def test_auth_user(self):
59 user = factory.make_User()
60 handler = UserHandler(user, {}, None)
61diff --git a/src/maasserver/websockets/handlers/user.py b/src/maasserver/websockets/handlers/user.py
62index 97f14fd..cba0ce6 100644
63--- a/src/maasserver/websockets/handlers/user.py
64+++ b/src/maasserver/websockets/handlers/user.py
65@@ -1,4 +1,4 @@
66-# Copyright 2015-2018 Canonical Ltd. This software is licensed under the
67+# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
68 # GNU Affero General Public License version 3 (see the file LICENSE).
69
70 """The user handler for the WebSocket connection."""
71@@ -35,7 +35,8 @@ class UserHandler(Handler):
72 queryset = (
73 User.objects.filter(is_active=True)
74 .annotate(
75- sshkeys_count=Count("sshkey"), machines_count=Count("node")
76+ sshkeys_count=Count("sshkey", distinct=True),
77+ machines_count=Count("node", distinct=True),
78 )
79 .select_related("userprofile")
80 )

Subscribers

People subscribed via source and target branches