Merge lp:~allenap/maas/notifications-triggers into lp:~maas-committers/maas/trunk

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: 5646
Proposed branch: lp:~allenap/maas/notifications-triggers
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 177 lines (+141/-0)
3 files modified
src/maasserver/triggers/tests/test_init.py (+4/-0)
src/maasserver/triggers/tests/test_websocket_listener.py (+86/-0)
src/maasserver/triggers/websocket.py (+51/-0)
To merge this branch: bzr merge lp:~allenap/maas/notifications-triggers
Reviewer Review Type Date Requested Status
Lee Trager (community) Approve
Review via email: mp+314606@code.launchpad.net

Commit message

Database triggers for the Notification and NotificationDismissal models.

To post a comment you must log in.
Revision history for this message
Lee Trager (ltrager) :
review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1.7 MiB)

The attempt to merge lp:~allenap/maas/notifications-triggers into lp:maas failed. Below is the output from the failed tests.

Get:1 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
Hit:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Get:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Fetched 204 kB in 0s (459 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind avahi-utils bash bind9 bind9utils build-essential bzr bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common isc-dhcp-server libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libnss-wrapper libpq-dev make nodejs-legacy npm postgresql pxelinux python3-all python3-apt python3-attr python3-bson python3-convoy python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-netaddr python3-netifaces python3-novaclient python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-simplejson python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
authbind is already the newest version (2.1.1+nmu1).
avahi-utils is already the newest version (0.6.32~rc+dfsg-1ubuntu2).
build-essential is already the newest version (12.1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu3).
distro-info is already the newest version (0.14build1).
git is already the newest version (1:2.7.4-0ubuntu1).
libjs-angularjs is already the newest version (1.2.28-1ubuntu2).
libjs-jquery is already the newest version (1.11.3+dfsg-4).
libjs-yui3-full is already the newest version (3.5.1-1ubuntu3).
libjs-yui3-min is already the newest version (3.5.1-1ubuntu3).
make is already the newest version (4.1-6).
postgresql is already the newest version (9.5+173).
pxelinux is already the newest version (3:6.03+dfsg-11ubuntu1).
python-formencode is already the newest version (1.3.0-0ubuntu5).
python-lxml is already the newest version (3.5.0-1build1).
python-netaddr is already the newest version (0.7.18-1).
python-netifaces is already the newest version (0.10.4-0.1build2).
python-psycopg2 ...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/triggers/tests/test_init.py'
2--- src/maasserver/triggers/tests/test_init.py 2017-01-10 13:34:54 +0000
3+++ src/maasserver/triggers/tests/test_init.py 2017-01-20 15:33:18 +0000
4@@ -183,6 +183,10 @@
5 "node_region_controller_update_notify",
6 "node_tags_machine_device_tag_link_notify",
7 "node_tags_machine_device_tag_unlink_notify",
8+ "notification_notification_create_notify",
9+ "notification_notification_delete_notify",
10+ "notification_notification_update_notify",
11+ "notificationdismissal_notificationdismissal_create_notify",
12 "packagerepository_packagerepository_create_notify",
13 "packagerepository_packagerepository_delete_notify",
14 "packagerepository_packagerepository_update_notify",
15
16=== modified file 'src/maasserver/triggers/tests/test_websocket_listener.py'
17--- src/maasserver/triggers/tests/test_websocket_listener.py 2016-12-07 14:53:00 +0000
18+++ src/maasserver/triggers/tests/test_websocket_listener.py 2017-01-20 15:33:18 +0000
19@@ -3246,3 +3246,89 @@
20 finally:
21 yield listener1.stopService()
22 yield listener2.stopService()
23+
24+
25+class TestNotificationListener(
26+ MAASTransactionServerTestCase, TransactionalHelpersMixin):
27+ """Tests for notifications relating to the `Notification` model."""
28+
29+ @wait_for_reactor
30+ @inlineCallbacks
31+ def test__calls_handler_on_create_notification(self):
32+ yield deferToDatabase(register_websocket_triggers)
33+ listener = self.make_listener_without_delay()
34+ dv = DeferredValue()
35+ listener.register("notification", lambda *args: dv.set(args))
36+ yield listener.startService()
37+ try:
38+ notification = yield deferToDatabase(factory.make_Notification)
39+ yield dv.get(timeout=2)
40+ self.assertEqual(('create', '%s' % notification.id), dv.value)
41+ finally:
42+ yield listener.stopService()
43+
44+ @wait_for_reactor
45+ @inlineCallbacks
46+ def test__calls_handler_on_update_notification(self):
47+ yield deferToDatabase(register_websocket_triggers)
48+ listener = self.make_listener_without_delay()
49+ dv = DeferredValue()
50+ listener.register("notification", lambda *args: dv.set(args))
51+ notification = yield deferToDatabase(factory.make_Notification)
52+
53+ def update_notification(notification):
54+ notification.users = not notification.users
55+ notification.admins = not notification.admins
56+ notification.save()
57+
58+ yield listener.startService()
59+ try:
60+ yield deferToDatabase(update_notification, notification)
61+ yield dv.get(timeout=2)
62+ self.assertEqual(('update', '%s' % notification.id), dv.value)
63+ finally:
64+ yield listener.stopService()
65+
66+ @wait_for_reactor
67+ @inlineCallbacks
68+ def test__calls_handler_on_delete_notification(self):
69+ yield deferToDatabase(register_websocket_triggers)
70+ listener = self.make_listener_without_delay()
71+ dv = DeferredValue()
72+ listener.register("notification", lambda *args: dv.set(args))
73+ notification = yield deferToDatabase(factory.make_Notification)
74+ notification_id = notification.id # Capture before delete.
75+ yield listener.startService()
76+ try:
77+ yield deferToDatabase(notification.delete)
78+ yield dv.get(timeout=2)
79+ self.assertEqual(('delete', '%s' % notification_id), dv.value)
80+ finally:
81+ yield listener.stopService()
82+
83+
84+class TestNotificationDismissalListener(
85+ MAASTransactionServerTestCase, TransactionalHelpersMixin):
86+ """Tests relating to the `NotificationDismissal` model.
87+
88+ At present `NotificationDismissal` rows are only ever created.
89+ """
90+
91+ @wait_for_reactor
92+ @inlineCallbacks
93+ def test__calls_handler_on_create_notification(self):
94+ yield deferToDatabase(register_websocket_triggers)
95+ listener = self.make_listener_without_delay()
96+ dv = DeferredValue()
97+ listener.register("notificationdismissal", lambda *args: dv.set(args))
98+ yield listener.startService()
99+ try:
100+ user = yield deferToDatabase(factory.make_User)
101+ notification = yield deferToDatabase(factory.make_Notification)
102+ yield deferToDatabase(notification.dismiss, user)
103+ yield dv.get(timeout=2)
104+ self.assertEqual(
105+ ('create', '%d:%d' % (notification.id, user.id)),
106+ dv.value)
107+ finally:
108+ yield listener.stopService()
109
110=== modified file 'src/maasserver/triggers/websocket.py'
111--- src/maasserver/triggers/websocket.py 2017-01-10 13:11:08 +0000
112+++ src/maasserver/triggers/websocket.py 2017-01-20 15:33:18 +0000
113@@ -960,6 +960,30 @@
114 region_and_rack_controller=NODE_TYPE.REGION_AND_RACK_CONTROLLER))
115
116
117+def render_notification_dismissal_notification_procedure(
118+ proc_name, event_name):
119+ """Send the notification_id and user_id when a notification is dismissed.
120+
121+ Why not send the surrogate primary key as we do for most/all other models?
122+ The surrogate primary key exists only because Django won't let us do
123+ without. It's just not interesting. We only want the notification's ID and
124+ the user's ID, and we may as well put those in the notification because
125+ they're really short and it saves an extra trip to the database to load
126+ the row.
127+ """
128+ return dedent("""\
129+ CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
130+ DECLARE
131+ BEGIN
132+ PERFORM pg_notify(
133+ '%s', CAST(NEW.notification_id AS text) || ':' ||
134+ CAST(NEW.user_id AS text));
135+ RETURN NEW;
136+ END;
137+ $$ LANGUAGE plpgsql;
138+ """ % (proc_name, event_name))
139+
140+
141 @transactional
142 def register_websocket_triggers():
143 """Register all websocket triggers into the database."""
144@@ -1736,6 +1760,33 @@
145 "maasserver_packagerepository", "packagerepository_delete_notify",
146 "delete")
147
148+ # Node type change.
149 register_procedure(node_type_change())
150 register_trigger(
151 "maasserver_node", "node_type_change_notify", "update")
152+
153+ # Notification table.
154+ register_procedure(
155+ render_notification_procedure(
156+ 'notification_create_notify', 'notification_create', 'NEW.id'))
157+ register_procedure(
158+ render_notification_procedure(
159+ 'notification_update_notify', 'notification_update', 'NEW.id'))
160+ register_procedure(
161+ render_notification_procedure(
162+ 'notification_delete_notify', 'notification_delete', 'OLD.id'))
163+ register_trigger(
164+ "maasserver_notification", "notification_create_notify", "insert")
165+ register_trigger(
166+ "maasserver_notification", "notification_update_notify", "update")
167+ register_trigger(
168+ "maasserver_notification", "notification_delete_notify", "delete")
169+
170+ # NotificationDismissal table.
171+ register_procedure(
172+ render_notification_dismissal_notification_procedure(
173+ 'notificationdismissal_create_notify',
174+ 'notificationdismissal_create'))
175+ register_trigger(
176+ "maasserver_notificationdismissal",
177+ "notificationdismissal_create_notify", "insert")