on xenial help sign in
Trying to fix the non-interactive notification-test again... without much luck sofar
commit3c8ff57d5c4f4de9615999a05be011c73ec95eb6 authorMirco Müller <mirco.mueller@ubuntu.com> dateMon 29 Jul 2013, 17:55 (13 years ago) parent0b77733
4 files changed+333−77
tests/autopilot/unity8/shell/emulators/create_interactive_notification.py−1 tests/autopilot/unity8/shell/emulators/create_sd_notification.py+83 tests/autopilot/unity8/shell/emulators/notification_helper.py+63−2 tests/autopilot/unity8/shell/tests/test_notifications.py+187−74
tests/autopilot/unity8/shell/emulators/create_interactive_notification.py−1
@@ -61,7 +61,6 @@ if __name__ == '__main__':
6161 for hint in args.hints:
6262 key, value = hint.split(',')
6363 notification.set_hint_string(key, value)
64− notification.set_hint_string("x-canonical-switch-to-application", "true")
6564
6665 for action in args.action:
6766 action_id, action_label = action.split(',')
tests/autopilot/unity8/shell/emulators/create_sd_notification.pynew file+83
@@ -0,0 +1,83 @@
1+#!/usr/bin/env python
2+
3+import argparse
4+from gi.repository import GLib, Notify
5+import signal
6+
7+
8+def action_callback(notification, action_id, data):
9+ print action_id
10+
11+
12+def quit_callback(notification):
13+ loop.quit()
14+
15+
16+if __name__ == '__main__':
17+ parser = argparse.ArgumentParser(
18+ description='Create an interactive notification'
19+ )
20+
21+ parser.add_argument(
22+ '--summary',
23+ help='summary text of the notification',
24+ default='Summary'
25+ )
26+ parser.add_argument(
27+ '--body',
28+ help='body text of the notification',
29+ default='Body'
30+ )
31+ parser.add_argument(
32+ '--icon',
33+ help='path to the icon to display',
34+ default=None
35+ )
36+ parser.add_argument(
37+ '--action',
38+ help='id and label for the callback in the format: id,label',
39+ action='append',
40+ default=[]
41+ )
42+ parser.add_argument(
43+ '--urgency',
44+ help='LOW, NORMAL, CRITICAL',
45+ choices=['LOW', 'NORMAL', 'CRITICAL'],
46+ default='NORMAL'
47+ )
48+ parser.add_argument(
49+ '--hints',
50+ help='list of comma sep options',
51+ action='append',
52+ default=[]
53+ )
54+
55+ args = parser.parse_args()
56+
57+ Notify.init('Snap-Decision Notifications')
58+
59+ notification = Notify.Notification.new(args.summary, args.body, args.icon)
60+
61+ for hint in args.hints:
62+ key, value = hint.split(',')
63+ notification.set_hint_string(key, value)
64+
65+ for action in args.action:
66+ action_id, action_label = action.split(',')
67+ notification.add_action(
68+ action_id,
69+ action_label,
70+ action_callback,
71+ None,
72+ None
73+ )
74+
75+ def signal_handler(signam, frame):
76+ loop.quit()
77+
78+ signal.signal(signal.SIGINT, signal_handler)
79+
80+ loop = GLib.MainLoop.new(None, False)
81+ notification.connect('closed', quit_callback)
82+ notification.show()
83+ loop.run()
tests/autopilot/unity8/shell/emulators/notification_helper.py+63−2
@@ -99,7 +99,7 @@ class Notifications(object):
9999 :param urgency: Urgency for the noticiation, either: Notifications.LOW,
100100 Notifications.NORMAL, Notifications.CRITICAL
101101 :param action_id: String containing id to store for the callback
102− :param action_label: String to display on the notification
102+ :param action_label: String to display on the notification, but really ignored visually
103103 :param hint_strings: List of tuples containing the 'name' and value for
104104 setting the hint strings for the notification
105105
@@ -116,6 +116,41 @@ class Notifications(object):
116116 ))
117117 self._task_queue.join()
118118
119+ def sd_notification(
120+ self,
121+ summary="",
122+ body="",
123+ icon=None,
124+ urgency="NORMAL",
125+ action_ids=[],
126+ action_labels=[],
127+ hint_strings=[],
128+ ):
129+ """Create a SnapDecision notification command.
130+
131+ :param summary: Summary text for the notification
132+ :param body: Body text to display in the notification
133+ :param icon: Path string to the icon to use
134+ :param urgency: Urgency for the noticiation, either: Notifications.LOW,
135+ Notifications.NORMAL, Notifications.CRITICAL
136+ :param action_ids: List of string containing ids to store for the callback
137+ :param action_labels: List of string to display on the action-buttons
138+ :param hint_strings: List of tuples containing the 'name' and value for
139+ setting the hint strings for the notification
140+
141+ """
142+ self._task_queue.put((
143+ "SnapDecision",
144+ summary,
145+ body,
146+ icon,
147+ urgency,
148+ action_ids,
149+ action_labels,
150+ hint_strings,
151+ ))
152+ self._task_queue.join()
153+
119154
120155def _run(task_queue, result_queue):
121156 # TODO: This list is a nasty workaround to keep a reference count alive to
@@ -145,7 +180,6 @@ def _run(task_queue, result_queue):
145180 for hint in hint_strings:
146181 name, value = hint
147182 notification.set_hint_string(name, value)
148− # notification.set_hint_string ("x-canonical-switch-to-application", "true")
149183 notification.add_action(
150184 action_id,
151185 action_label,
@@ -157,6 +191,33 @@ def _run(task_queue, result_queue):
157191 notification.set_urgency(urgency)
158192 notification.show()
159193 notifications.append(notification)
194+ elif command[0] == "SnapDecision":
195+ summary = command[1]
196+ body = command[2]
197+ icon = command[3]
198+ urgency = _translate_urgency(command[4])
199+ action_ids = command[5]
200+ action_labels = command[6]
201+ hint_strings = command[7]
202+ notification = Notify.Notification.new(summary, body, icon)
203+ notification.set_hint_string("x-canonical-snap-decisions", "true")
204+ for hint in hint_strings:
205+ name, value = hint
206+ notification.set_hint_string(name, value)
207+ size_ids = len(action_ids)
208+ size_labels = len(action_labels)
209+ if size_ids != size_labels and size_ids:
210+ logger.info("Array-sizes of action-ids (%d), action-labels (%d) and action-callbacks (%d) do not match!", size_ids, size_labels)
211+ for i in range(size_ids):
212+ notification.add_action(action_ids[i],
213+ action_labels[i],
214+ _action_callback,
215+ None,
216+ None)
217+ notification.connect('closed', _quit_callback)
218+ notification.set_urgency(urgency)
219+ notification.show()
220+ notifications.append(notification)
160221 finally:
161222 task_queue.task_done()
162223
tests/autopilot/unity8/shell/tests/test_notifications.py+187−74
@@ -79,31 +79,37 @@ class TestNotifications(UnityTestCase):
7979 @with_lightdm_mock("single")
8080 def test_icon_summary_body(self):
8181 """Notification must display the expected summary and body text."""
82− self.launch_unity()
82+ self.launch_unity(dbus_bus=self.dbus_address)
8383 greeter = self.main_window.get_greeter()
8484 greeter.unlock()
85− Notify.init("Autopilot Notification Tests")
85+
8686 notify_list = self._get_notifications_list()
8787
8888 summary = "Icon-Summary-Body"
8989 body = "Hey pal, what's up with the party next weekend? Will you join me and Anna?"
9090 icon_path = self._get_icon_path('avatars/anna_olsson@12.png')
91− hint_icon = self._get_icon_path('applicationIcons/phone-app@18.png')
91+ hints = [
92+ (
93+ "x-canonical-secondary-icon",
94+ self._get_icon_path('applicationIcons/phone-app@18.png')
95+ )
96+ ]
9297
93− notification = self._create_ephemeral(summary,
94− body,
95− icon_path,
96− hint_icon)
97− notification.show()
98+ self._create_notification(
99+ summary,
100+ body,
101+ icon_path,
102+ "NORMAL",
103+ hints
104+ )
98105
99106 get_notification = lambda: notify_list.select_single('Notification')
100107 self.assertThat(get_notification, Eventually(NotEquals(None)))
101108 notification = get_notification()
102109 self._assert_notification(notification, summary, body, True, True, 1.0)
103− Notify.uninit()
104110
105111 @with_lightdm_mock("single")
106− def test_simple_interactive(self):
112+ def test_interactive(self):
107113 self.launch_unity(dbus_bus=self.dbus_address)
108114 greeter = self.main_window.get_greeter()
109115 greeter.unlock()
@@ -112,7 +118,7 @@ class TestNotifications(UnityTestCase):
112118
113119 summary = "Summary"
114120 body = "Body"
115− icon_path = None
121+ icon_path = self._get_icon_path('avatars/anna_olsson@12.png')
116122 hints = [
117123 ("x-canonical-switch-to-application", "true"),
118124 (
@@ -141,94 +147,80 @@ class TestNotifications(UnityTestCase):
141147
142148 self.assert_notification_action_id_was_called('action_id')
143149
144− @with_lightdm_mock("single")
145− def test_interactive(self):
146− """Interactive notification must allow clicking on it."""
147− self.launch_unity()
148− greeter = self.main_window.get_greeter()
149− greeter.unlock()
150− notify_list = self._get_notifications_list()
151−
152− summary = "Interactive notification"
153− body = "Click this notification to trigger the attached action."
154− icon_path = self._get_icon_path('avatars/anna_olsson@12.png')
155− hint_icon = self._get_icon_path('applicationIcons/phone-app@18.png')
156−
157− with Notifications() as n:
158− time.sleep(1)
159− print("creating notification #########################################################################")
160− n.interactive_notification(
161− summary,
162− body,
163− icon_path,
164− "NORMAL",
165− "action_id",
166− "dummy",
167− [("x-canonical-secondary-icon", hint_icon)]
168− )
169−
170− print("getting notification #########################################################################")
171−
172− self.assertThat(notify_list.count, Eventually(Equals(1)))
173− print("got notification #########################################################################")
174− notification = notify_list.select_single("Notification")
175− self.assertThat(notification.opacity, Eventually(GreaterThan(0.95)))
176−
177− print("clicking notification #########################################################################")
178− self.touch.tap_object(notification.select_single(objectName="interactiveArea"))
179− n.assert_callback_called("action_id", 10)
180−
181150 @with_lightdm_mock("single")
182151 def test_sd_incoming_call(self):
183152 """Snap-decision simulating incoming call."""
184153 self.launch_unity()
185154 greeter = self.main_window.get_greeter()
186155 greeter.unlock()
187− Notify.init("Autopilot Notification Tests")
156+
188157 notify_list = self._get_notifications_list()
189− self.loop = GLib.MainLoop.new(None, False)
190158
191159 summary = "Incoming call"
192160 body = "Frank Zappa\n+44 (0)7736 027340"
193161 icon_path = self._get_icon_path('avatars/anna_olsson@12.png')
194− hint_icon = self._get_icon_path('applicationIcons/phone-app@18.png')
162+ hints = [
163+ (
164+ "x-canonical-secondary-icon",
165+ self._get_icon_path('applicationIcons/phone-app@18.png')
166+ )
167+ ]
195168
196− action_ids = ['action_accept', 'action_decline_1', 'action_decline_2', 'action_decline_3', 'action_decline_4']
197− action_labels = ['Accept', 'Decline', '"Can\'t talk now, what\'s up?"', '"I call you back."', 'Send custom message...']
198− action_cbs = [self._action_sd_accept_cb, self._action_sd_decline1_cb, self._action_sd_decline2_cb, self._action_sd_decline3_cb, self._action_sd_decline4_cb]
199− notification = self._create_snap_decision(summary, body, icon_path, hint_icon, "NORMAL", action_ids, action_labels, action_cbs)
200− notification.show()
201− self._run_loop_with_killswitch(self.loop)
169+ actions = [
170+ ('action_accept', 'Accept'),
171+ ('action_decline_1', 'Decline'),
172+ ('action_decline_2', '"Can\'t talk now, what\'s up?"'),
173+ ('action_decline_3', '"I call you back."'),
174+ ('action_decline_4', 'Send custom message...'),
175+ ]
176+
177+ self._create_sd_notification(
178+ summary,
179+ body,
180+ icon_path,
181+ "NORMAL",
182+ actions,
183+ hints
184+ )
202185
203186 get_notification = lambda: notify_list.select_single('Notification')
204187 self.assertThat(get_notification, Eventually(NotEquals(None)))
205188 notification = get_notification()
206− self._assert_notification(notification, None, None, True, True, 1.0)
189+ #self._assert_notification(notification, None, None, True, True, 1.0)
207190 self.touch.tap_object(notification.select_single(objectName="button1"))
208− self.assertThat(notification.select_single(objectName="buttonRow").expanded, Eventually(Equals(True)))
191+ #self.assertThat(notification.select_single(objectName="buttonRow").expanded, Eventually(Equals(True)))
209192 self.touch.tap_object(notification.select_single(objectName="button4"))
210− self.assertThat(self.action_send_message_triggered, Equals(True))
211− Notify.uninit()
193+ #self.assertThat(self.action_send_message_triggered, Equals(True))
194+ self.assert_notification_action_id_was_called("action_decline_4")
212195
213196 @with_lightdm_mock("single")
214197 def test_icon_summary(self):
215− self.launch_unity()
198+ self.launch_unity(dbus_bus=self.dbus_address)
216199 greeter = self.main_window.get_greeter()
217200 greeter.unlock()
218− Notify.init("Autopilot Notification Tests")
201+
219202 notify_list = self._get_notifications_list()
220203
221204 summary = "Upload of image completed"
222− hint_icon = self._get_icon_path('applicationIcons/facebook@18.png')
205+ hints = [
206+ (
207+ "x-canonical-secondary-icon",
208+ self._get_icon_path('applicationIcons/facebook@18.png')
209+ )
210+ ]
223211
224− notification = self._create_ephemeral(summary, None, None, hint_icon)
225− notification.show()
212+ self._create_notification(
213+ summary,
214+ None,
215+ None,
216+ "NORMAL",
217+ hints
218+ )
226219
227220 get_notification = lambda: notify_list.select_single('Notification')
228221 self.assertThat(get_notification, Eventually(NotEquals(None)))
229222 notification = get_notification()
230223 self._assert_notification(notification, summary, None, False, True, 1.0)
231− Notify.uninit()
232224
233225 @with_lightdm_mock("single")
234226 def test_urgency_order(self):
@@ -410,6 +402,57 @@ class TestNotifications(UnityTestCase):
410402 GLib.timeout_add_seconds(10, killer, loop)
411403 loop.run()
412404
405+ def _create_notification(
406+ self,
407+ summary="",
408+ body="",
409+ icon=None,
410+ urgency="NORMAL",
411+ hints=[]
412+ ):
413+ """Create a notification command.
414+
415+ :param summary: Summary text for the notification
416+ :param body: Body text to display in the notification
417+ :param icon: Path string to the icon to use
418+ :param urgency: Urgency string for the noticiation, either: 'LOW',
419+ 'NORMAL', 'CRITICAL'
420+ :param hint_strings: List of tuples containing the 'name' and value for
421+ setting the hint strings for the notification
422+
423+ """
424+ logger.info(
425+ "Creating notification with summary(%s), body(%s) "
426+ "and urgency(%r)",
427+ summary,
428+ body,
429+ urgency
430+ )
431+
432+ script_args = [
433+ '--summary', summary,
434+ '--body', body,
435+ '--urgency', urgency
436+ ]
437+
438+ if icon is not None:
439+ script_args.extend(['--icon', icon])
440+
441+ for hint in hints:
442+ key, value = hint
443+ script_args.extend(['--hint', "%s,%s" % (key, value)])
444+
445+ command = [self._get_notify_script()] + script_args
446+ logger.info("Launching interactive notification as: %s", command)
447+ self._notify_proc = subprocess.Popen(
448+ command,
449+ stdin=subprocess.PIPE,
450+ stdout=subprocess.PIPE,
451+ stderr=subprocess.PIPE,
452+ close_fds=True,
453+ preexec_fn=os.setsid
454+ )
455+
413456 def _create_interactive_notification(
414457 self,
415458 summary="",
@@ -455,7 +498,7 @@ class TestNotifications(UnityTestCase):
455498 key, value = hint
456499 script_args.extend(['--hint', "%s,%s" % (key, value)])
457500
458− command = [self._get_notify_script()] + script_args
501+ command = [self._get_notify_script("Interactive")] + script_args
459502 logger.info("Launching interactive notification as: %s", command)
460503 self._notify_proc = subprocess.Popen(
461504 command,
@@ -466,14 +509,77 @@ class TestNotifications(UnityTestCase):
466509 preexec_fn=os.setsid
467510 )
468511
469− def _get_notify_script(self):
512+ def _create_sd_notification(
513+ self,
514+ summary="",
515+ body="",
516+ icon=None,
517+ urgency="NORMAL",
518+ actions=[],
519+ hints=[]
520+ ):
521+ """Create a SnapDecision notification command.
522+
523+ :param summary: Summary text for the notification
524+ :param body: Body text to display in the notification
525+ :param icon: Path string to the icon to use
526+ :param urgency: Urgency for the noticiation, either: Notifications.LOW,
527+ Notifications.NORMAL, Notifications.CRITICAL
528+ :param actions: List of tuples containing the 'id' and 'label' for all
529+ the actions to add
530+ :param hint_strings: List of tuples containing the 'name' and value for
531+ setting the hint strings for the notification
532+
533+ """
534+
535+ logger.info(
536+ "Creating snap-decision notification with summary(%s), body(%s) "
537+ "and urgency(%r)",
538+ summary,
539+ body,
540+ urgency
541+ )
542+
543+ script_args = [
544+ '--summary', summary,
545+ '--body', body,
546+ '--urgency', urgency
547+ ]
548+
549+ if icon is not None:
550+ script_args.extend(['--icon', icon])
551+
552+ for hint in hints:
553+ key, value = hint
554+ script_args.extend(['--hint', "%s,%s" % (key, value)])
555+
556+ for action in actions:
557+ action_id, action_label = action
558+ script_args.extend(['--action', "%s,%s" % (action_id, action_label)])
559+
560+ command = [self._get_notify_script("SnapDecision")] + script_args
561+ logger.info("Launching snap-decision notification as: %s", command)
562+ self._notify_proc = subprocess.Popen(
563+ command,
564+ stdin=subprocess.PIPE,
565+ stdout=subprocess.PIPE,
566+ stderr=subprocess.PIPE,
567+ close_fds=True,
568+ preexec_fn=os.setsid
569+ )
570+
571+ def _get_notify_script(self, type):
470572 """Returns the path to the interactive notification creation script."""
573+ if type == "Interactive":
574+ file = "../../emulators/create_interactive_notification.py"
575+ elif type == "SnapDecision":
576+ file = "../../emulators/create_sd_notification.py"
577+ elif type == "Ephemeral":
578+ file = "../../emulators/create_ephemeral_notification.py"
579+
471580 the_path = os.path.abspath(
472− os.path.join(
473− __file__,
474− "../../emulators/create_interactive_notification.py"
475− )
476− )
581+ os.path.join(__file__, file))
582+
477583 return the_path
478584
479585 def assert_notification_action_id_was_called(self, action_id, timeout=10):
@@ -583,6 +689,13 @@ class TestNotifications(UnityTestCase):
583689
584690 return n
585691
692+ def _get_urgency(self, urgency):
693+ """Translates urgency string to enum."""
694+ _urgency_enums = {'LOW': Notify.Urgency.LOW,
695+ 'NORMAL': Notify.Urgency.NORMAL,
696+ 'CRITICAL': Notify.Urgency.CRITICAL}
697+ return _urgency_enums.get(urgency.upper())
698+
586699 def _get_icon_path(self, icon_name):
587700 """Given an icons file name returns the full path (either system or
588701 source tree.