Merge ~adam-collard/maas:fix-1884112-count-aggregate into maas:master

Proposed by Adam Collard
Status: Merged
Approved by: Adam Collard
Approved revision: 5fa7469193404631d52032fee086dcd4efc6b1f5
Merged at revision: 020f9684cb4181535de0ccd5c299a093be8b5100
Proposed branch: ~adam-collard/maas:fix-1884112-count-aggregate
Merge into: maas:master
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
Björn Tillenius Approve
MAAS Lander Approve
Dougal Matthews (community) Approve
Review via email: mp+386092@code.launchpad.net

Commit message

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
Dougal Matthews (d0ugal) :
review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b fix-1884112-count-aggregate lp:~adam-collard/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/7747/console
COMMIT: 5e3dcfa4f3678788e3303c037a91035f80c44f09

review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :
Revision history for this message
Björn Tillenius (bjornt) :
review: Needs Information
5fa7469... by Adam Collard

Make the expectation about num keys, machines clear (BjornT's review)

Revision history for this message
Adam Collard (adam-collard) :
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b fix-1884112-count-aggregate lp:~adam-collard/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 5fa7469193404631d52032fee086dcd4efc6b1f5

review: Approve
Revision history for this message
Björn Tillenius (bjornt) wrote :

+1 with a nitpick inline

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/websockets/handlers/tests/test_user.py b/src/maasserver/websockets/handlers/tests/test_user.py
index 2eaecaa..f62c79c 100644
--- a/src/maasserver/websockets/handlers/tests/test_user.py
+++ b/src/maasserver/websockets/handlers/tests/test_user.py
@@ -1,4 +1,4 @@
1# Copyright 2015-2018 Canonical Ltd. This software is licensed under the1# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for `maasserver.websockets.handlers.user`"""4"""Tests for `maasserver.websockets.handlers.user`"""
@@ -10,6 +10,7 @@ import datetime
10from django.contrib.auth.models import User10from django.contrib.auth.models import User
11from testtools.testcase import TestCase11from testtools.testcase import TestCase
1212
13from maasserver.enum import NODE_STATUS
13from maasserver.models.event import Event14from maasserver.models.event import Event
14from maasserver.models.user import SYSTEM_USERS15from maasserver.models.user import SYSTEM_USERS
15from maasserver.permissions import (16from maasserver.permissions import (
@@ -64,15 +65,17 @@ class TestUserHandler(MAASServerTestCase):
64 # testtools' assertRaises predates unittest's which has65 # testtools' assertRaises predates unittest's which has
65 # support for context-manager66 # support for context-manager
66 self.assertRaises = super(TestCase, self).assertRaises67 self.assertRaises = super(TestCase, self).assertRaises
68 # likewise assertEqual in unittest has gotten much better
69 self.assertEqual = super(TestCase, self).assertEqual
6770
68 def dehydrate_user(self, user, sshkeys_count=0, for_self=False):71 def dehydrate_user(self, user, for_self=False):
69 data = {72 data = {
70 "id": user.id,73 "id": user.id,
71 "username": user.username,74 "username": user.username,
72 "last_name": user.last_name,75 "last_name": user.last_name,
73 "email": user.email,76 "email": user.email,
74 "is_superuser": user.is_superuser,77 "is_superuser": user.is_superuser,
75 "sshkeys_count": sshkeys_count,78 "sshkeys_count": user.sshkey_set.count(),
76 "last_login": dehydrate_datetime(user.last_login),79 "last_login": dehydrate_datetime(user.last_login),
77 "is_local": user.userprofile.is_local,80 "is_local": user.userprofile.is_local,
78 "completed_intro": user.userprofile.completed_intro,81 "completed_intro": user.userprofile.completed_intro,
@@ -163,6 +166,21 @@ class TestUserHandler(MAASServerTestCase):
163 [self.dehydrate_user(user, for_self=True)], handler.list({})166 [self.dehydrate_user(user, for_self=True)], handler.list({})
164 )167 )
165168
169 def test_list_with_sshkeys_and_machines(self):
170 user, keys = factory.make_user_with_keys()
171 num_machines = 3
172 for _ in range(num_machines):
173 node = factory.make_Node(status=NODE_STATUS.READY)
174 node.acquire(user)
175 handler = UserHandler(user, {}, None)
176 users_from_ws = handler.list({})
177 self.assertEqual(
178 [self.dehydrate_user(user, for_self=True)], users_from_ws
179 )
180 user_from_ws = users_from_ws[0]
181 self.assertEqual(user_from_ws["sshkeys_count"], len(keys))
182 self.assertEqual(user_from_ws["machines_count"], num_machines)
183
166 def test_auth_user(self):184 def test_auth_user(self):
167 user = factory.make_User()185 user = factory.make_User()
168 handler = UserHandler(user, {}, None)186 handler = UserHandler(user, {}, None)
diff --git a/src/maasserver/websockets/handlers/user.py b/src/maasserver/websockets/handlers/user.py
index 269d334..7a12ac0 100644
--- a/src/maasserver/websockets/handlers/user.py
+++ b/src/maasserver/websockets/handlers/user.py
@@ -1,4 +1,4 @@
1# Copyright 2015-2018 Canonical Ltd. This software is licensed under the1# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""The user handler for the WebSocket connection."""4"""The user handler for the WebSocket connection."""
@@ -35,7 +35,8 @@ class UserHandler(Handler):
35 queryset = (35 queryset = (
36 User.objects.filter(is_active=True)36 User.objects.filter(is_active=True)
37 .annotate(37 .annotate(
38 sshkeys_count=Count("sshkey"), machines_count=Count("node")38 sshkeys_count=Count("sshkey", distinct=True),
39 machines_count=Count("node", distinct=True),
39 )40 )
40 .select_related("userprofile")41 .select_related("userprofile")
41 )42 )

Subscribers

People subscribed via source and target branches