Merge lp:~thisfred/ubuntuone-client/tune-notifications into lp:ubuntuone-client

Proposed by Eric Casteleijn
Status: Merged
Approved by: Eric Casteleijn
Approved revision: 935
Merged at revision: 927
Proposed branch: lp:~thisfred/ubuntuone-client/tune-notifications
Merge into: lp:ubuntuone-client
Diff against target: 789 lines (+75/-392)
4 files modified
tests/status/test_aggregator.py (+28/-270)
tests/syncdaemon/test_status_listener.py (+0/-26)
ubuntuone/status/aggregator.py (+46/-91)
ubuntuone/syncdaemon/status_listener.py (+1/-5)
To merge this branch: bzr merge lp:~thisfred/ubuntuone-client/tune-notifications
Reviewer Review Type Date Requested Status
dobey (community) Approve
Natalia Bidart (community) Approve
Review via email: mp+54510@code.launchpad.net

Commit message

* removed progress notifications
* don't show empty notifications
* only show queue_done notifications after a delay where no new events came in

Description of the change

* removed progress notifications
* don't show empty notifications
* only show queue_done notifications after a delay where no new events came in. (set to 5 seconds which seems to work well OMM)

To test:

  u1sdtool -q
  PYTHONPATH=. bin/ubuntuone-syncdaemon

now on a different machine, do a bzr checkout in your Ubuntu One folder. (Or do something else that adds a lot of small files relatively quickly.)

On the receiving machine, you should now no longer see many download finished messages popping up one after the other, but rather one at the end. If your connection is slow or the servers are having trouble, you *might* see more than one, but never more than one per 5 seconds. Let me know if we should tune that number further.

To post a comment you must log in.
Revision history for this message
Natalia Bidart (nataliabidart) :
review: Approve
Revision history for this message
dobey (dobey) wrote :

Looks sane to me. I might have picked 10s from past experience with this exact problem, but we'll see how 5s works. :)

review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (3.2 MiB)

The attempt to merge lp:~thisfred/ubuntuone-client/tune-notifications into lp:ubuntuone-client failed. Below is the output from the failed tests.

/usr/bin/gnome-autogen.sh
checking for autoconf >= 2.53...
  testing autoconf2.50... not found.
  testing autoconf... found 2.67
checking for automake >= 1.10...
  testing automake-1.11... found 1.11.1
checking for libtool >= 1.5...
  testing libtoolize... found 2.2.6b
checking for intltool >= 0.30...
  testing intltoolize... found 0.41.1
checking for pkg-config >= 0.14.0...
  testing pkg-config... found 0.25
checking for gtk-doc >= 1.0...
  testing gtkdocize... found 1.16
Checking for required M4 macros...
Checking for forbidden M4 macros...
Processing ./configure.ac
Running libtoolize...
libtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
Running intltoolize...
Running gtkdocize...
Running aclocal-1.11...
Running autoconf...
Running autoheader...
Running automake-1.11...
Running ./configure --enable-gtk-doc --enable-debug ...
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for style of include used by make... GNU
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking dependency style of gcc... gcc3
checking for library containing strerror... none required
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking dependency style of gcc... (cached) gcc3
checking build system type... i686-pc-linux-gnu
checking host system type... i686-pc-linux-gnu
checking for a sed that does not truncate output... /bin/sed
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for fgrep... /bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 1572864
checking whether the shell understands some XSI constructs... yes
checking whether the shell understands "+="... yes
checking for /usr/bin/ld option to reload object files... -r
checking for objdump... objdump
checking how to recognize dependent ...

935. By Eric Casteleijn

set the property before calling reset.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'tests/status/test_aggregator.py'
2--- tests/status/test_aggregator.py 2011-03-22 16:59:19 +0000
3+++ tests/status/test_aggregator.py 2011-03-23 20:01:28 +0000
4@@ -200,7 +200,6 @@
5 """Initialize this instance."""
6 self.discovered = 0
7 self.completed = 0
8- self.restart_progress_bubble_called = False
9 self.notification_switch = aggregator.NotificationSwitch()
10
11 def get_discovery_message(self):
12@@ -226,10 +225,6 @@
13 """Return the final status message."""
14 return "a lot of files completed."""
15
16- def restart_progress_bubble(self):
17- """Reset the progress bubble."""
18- self.restart_progress_bubble_called = True
19-
20 def get_notification(self):
21 """Create a new toggleable notification object."""
22 return self.notification_switch.get_notification()
23@@ -340,12 +335,6 @@
24 notification = (aggregator.UBUNTUONE_TITLE, message, None, False)
25 self.assertIn(notification, self.get_notifications_shown())
26
27- def test_popup_resets_progress_bubble(self):
28- """The popup callback resets the progress bubble."""
29- self.bubble.new_file_found()
30- self.bubble._popup()
31- self.assertTrue(self.aggregator.restart_progress_bubble_called)
32-
33 def test_notification_is_logged_in_debug(self):
34 """The notification is printed in the debug log."""
35 self.bubble.new_file_found()
36@@ -430,14 +419,6 @@
37 self.clock.advance(self.updates_delay)
38 self.assertEqual(2, len(self.get_notifications_shown()))
39
40- def test_update_resets_progress_bubble(self):
41- """The update callback resets the progress bubble."""
42- self.bubble.new_file_found()
43- self.bubble._popup()
44- self.bubble.new_file_found()
45- self.bubble._update()
46- self.assertTrue(self.aggregator.restart_progress_bubble_called)
47-
48 def test_update_modifies_notification(self):
49 """The update callback updates notifications."""
50 self.bubble.new_file_found()
51@@ -458,91 +439,6 @@
52 self.assertTrue(self.handler.check_debug(msg))
53
54
55-class ProgressBubbleTestCase(TestCase):
56- """Tests for the progress bubble."""
57-
58- def setUp(self):
59- """Initialize this test instance."""
60- self.patch(aggregator, "ToggleableNotification",
61- FakeNotificationSingleton())
62- self.clock = PatchedClock()
63- self.aggregator = FakeStatusAggregator(clock=self.clock)
64- self.bubble = aggregator.ProgressBubble(self.aggregator,
65- clock=self.clock)
66- self.addCleanup(self.bubble.cleanup)
67- self.smaller_delay = aggregator.ProgressBubble.sleep_delay * 0.8
68- self.right_delay = aggregator.ProgressBubble.sleep_delay
69- self.longer_delay = aggregator.ProgressBubble.sleep_delay * 1.2
70-
71- def test_is_created_successfully(self):
72- """The progress bubble is created and idle."""
73- self.assertEqual(None, self.bubble.timer)
74-
75- def test_restart_creates_timer(self):
76- """Restarting creates a timer."""
77- self.bubble.restart()
78- self.assertNotEqual(None, self.bubble.timer)
79-
80- def test_not_shown_initially(self):
81- """The bubble is not shown initially."""
82- self.bubble.restart()
83- self.assertEqual(None, self.bubble.notification)
84-
85- def test_not_shown_immediately(self):
86- """The bubble is not shown immediately."""
87- self.bubble.restart()
88- self.clock.advance(self.smaller_delay)
89- self.assertEqual(None, self.bubble.notification)
90-
91- def test_shown_after_delay(self):
92- """The bubble is shown after the standard delay."""
93- self.bubble.restart()
94- self.clock.advance(self.longer_delay)
95- self.assertEqual(1, len(self.bubble.notification.notifications_shown))
96-
97- def test_not_shown_if_restarted(self):
98- """The delay is adjusted when restarting."""
99- self.bubble.restart()
100- self.clock.advance(self.smaller_delay)
101- self.bubble.restart()
102- self.clock.advance(self.smaller_delay)
103- self.assertEqual(None, self.bubble.notification)
104-
105- def test_delay_reached_after_restart(self):
106- """The timeout is still reached after a restart."""
107- self.bubble.restart()
108- self.clock.advance(self.smaller_delay)
109- self.bubble.restart()
110- self.clock.advance(self.longer_delay)
111- self.assertEqual(1, len(self.bubble.notification.notifications_shown))
112-
113- def test_can_be_stopped(self):
114- """The timeout can be stopped."""
115- self.bubble.restart()
116- self.clock.advance(self.smaller_delay)
117- self.bubble.stop()
118- self.clock.advance(self.longer_delay)
119- self.assertEqual(None, self.bubble.notification)
120-
121- def test_delay_reached_after_stopping_then_restarting(self):
122- """The timeout is still reached after a stop followed by a restart."""
123- self.bubble.restart()
124- self.clock.advance(self.smaller_delay)
125- self.bubble.stop()
126- self.clock.advance(self.longer_delay)
127- self.bubble.restart()
128- self.clock.advance(self.longer_delay)
129- self.assertEqual(1, len(self.bubble.notification.notifications_shown))
130-
131- def test_restarts_automatically(self):
132- """The timer is restarted automatically."""
133- self.bubble.restart()
134- self.clock.advance(self.right_delay)
135- self.assertEqual(1, len(self.bubble.notification.notifications_shown))
136- self.clock.advance(self.right_delay)
137- self.assertEqual(2, len(self.bubble.notification.notifications_shown))
138-
139-
140 class FinalBubbleTestCase(TestCase):
141 """Test for the final status notification bubble."""
142
143@@ -788,14 +684,6 @@
144 """The queue completed all operations."""
145 self.queued_commands.clear()
146
147- def misc_command_queued(self, command):
148- """A new command was queued."""
149- self.queued_commands.add(command)
150-
151- def misc_command_unqueued(self, command):
152- """A new command was unqueued."""
153- self.queued_commands.discard(command)
154-
155 def get_notification(self):
156 """Create a new toggleable notification object."""
157 return self.notification_switch.get_notification()
158@@ -803,24 +691,24 @@
159 def download_started(self, command):
160 """A download just started."""
161 self.files_downloading.append(command)
162- self.misc_command_queued(command)
163+ self.queued_commands.add(command)
164
165 def download_finished(self, command):
166 """A download just finished."""
167 if command in self.files_downloading:
168 self.files_downloading.remove(command)
169- self.misc_command_unqueued(command)
170+ self.queued_commands.discard(command)
171
172 def upload_started(self, command):
173 """An upload just started."""
174 self.files_uploading.append(command)
175- self.misc_command_queued(command)
176+ self.queued_commands.add(command)
177
178 def upload_finished(self, command):
179 """An upload just finished."""
180 if command in self.files_uploading:
181 self.files_uploading.remove(command)
182- self.misc_command_unqueued(command)
183+ self.queued_commands.discard(command)
184
185 def connection_made(self):
186 """The client made the connection to the server."""
187@@ -914,21 +802,6 @@
188 qc = self.status_frontend.aggregator.queued_commands
189 self.assertNotIn(fake_command, qc)
190
191- def test_queue_added(self):
192- """A command was added to the queue."""
193- fake_command = FakeCommand()
194- self.listener.handle_SYS_QUEUE_ADDED(fake_command)
195- qc = self.status_frontend.aggregator.queued_commands
196- self.assertIn(fake_command, qc)
197-
198- def test_queue_removed(self):
199- """A command has finished and is removed from the queue."""
200- fake_command = FakeCommand()
201- self.listener.handle_SYS_QUEUE_ADDED(fake_command)
202- self.listener.handle_SYS_QUEUE_REMOVED(fake_command)
203- qc = self.status_frontend.aggregator.queued_commands
204- self.assertNotIn(fake_command, qc)
205-
206 def test_queue_done(self):
207 """The queue is empty."""
208 fake_command = FakeCommand()
209@@ -1161,27 +1034,6 @@
210 """Cleanup this instance."""
211
212
213-class FakeProgressBubble(object):
214- """A fake ProgressBubble object."""
215-
216- started = False
217- stopped = False
218-
219- def __init__(self, status_aggregator, clock=None):
220- """Initialize this instance."""
221- self.status_aggregator = status_aggregator
222-
223- def cleanup(self):
224- """Cleanup this instance."""
225-
226- def restart(self):
227- """Start this bubble waiting."""
228- self.started = True
229-
230- def stop(self):
231- """Make this bubble stop."""
232-
233-
234 class FakeFinalBubble(object):
235 """A fake FinalStatusBubble."""
236
237@@ -1206,15 +1058,14 @@
238 """Initialize this test instance."""
239 self.patch(aggregator, "FileDiscoveryBubble",
240 FakeFileDiscoveryBubble)
241- self.patch(aggregator, "ProgressBubble",
242- FakeProgressBubble)
243 self.patch(aggregator, "FinalStatusBubble",
244 FakeFinalBubble)
245 self.patch(aggregator, "ToggleableNotification",
246 FakeNotificationSingleton())
247 self.patch(aggregator, "UbuntuOneLauncher", FakeLauncher)
248 self.patch(aggregator.session, "Inhibitor", FakeInhibitor)
249- self.status_frontend = aggregator.StatusFrontend()
250+ clock = PatchedClock()
251+ self.status_frontend = aggregator.StatusFrontend(clock=clock)
252 self.aggregator = self.status_frontend.aggregator
253 self.fake_bubble = self.aggregator.file_discovery_bubble
254
255@@ -1253,21 +1104,6 @@
256 """Test that the counters start at zero."""
257 self.assertStatusReset()
258
259- def test_misc_command_queue(self):
260- """Test that a misc command was queued."""
261- fc = FakeCommand()
262- self.status_frontend.queue_added(fc)
263- self.assertMiscCommandQueued(fc)
264- self.assertEqual(0, self.aggregator.progress_bar.progress)
265-
266- def test_misc_command_unqueue(self):
267- """Test that a misc command was unqueued."""
268- fc = FakeCommand()
269- self.status_frontend.queue_added(fc)
270- self.status_frontend.queue_removed(fc)
271- self.assertMiscCommandUnqueued(fc)
272- self.assertEqual(1.0, self.aggregator.progress_bar.progress)
273-
274 def test_file_download_started(self):
275 """Test that a file has started download."""
276 fc = FakeCommand(path='testfile.txt')
277@@ -1323,76 +1159,6 @@
278 result = self.aggregator.get_discovery_message()
279 self.assertEqual(expected, result)
280
281- def test_get_progress_message(self):
282- """Test the message that's shown on the progress bubble."""
283- self.aggregator.upload_done = 5
284- self.aggregator.upload_total = 10
285- self.aggregator.uploading_filename = FILENAME
286- self.aggregator.download_done = 3
287- self.aggregator.download_total = 8
288- self.aggregator.downloading_filename = FILENAME2
289- self.aggregator.done_counter = 9
290- self.aggregator.total_counter = 20
291- percentage = int(100.0 * self.aggregator.done_counter /
292- self.aggregator.total_counter)
293-
294- expected = (
295- aggregator.files_being_uploaded(
296- FILENAME, self.aggregator.upload_total) + "\n" +
297- aggregator.files_being_downloaded(
298- FILENAME2, self.aggregator.download_total) + "\n" +
299- aggregator.PROGRESS_COMPLETED) % {
300- 'percentage_completed': percentage}
301-
302- result = self.aggregator.get_progress_message()
303- self.assertEqual(expected, result)
304-
305- def test_get_progress_message_no_uploads(self):
306- """The progress message when no uploads are going on."""
307-
308- self.aggregator.upload_done = 0
309- self.aggregator.upload_total = 0
310- self.aggregator.downloading_filename = FILENAME
311- self.aggregator.download_done = 3
312- self.aggregator.download_total = 8
313- self.aggregator.done_counter = 9
314- self.aggregator.total_counter = 20
315- percentage = int(100.0 * self.aggregator.done_counter /
316- self.aggregator.total_counter)
317- expected = (
318- aggregator.files_being_downloaded(
319- FILENAME, self.aggregator.download_total) + "\n" +
320- aggregator.PROGRESS_COMPLETED) % {
321- 'percentage_completed': percentage}
322-
323- result = self.aggregator.get_progress_message()
324- self.assertEqual(expected, result)
325-
326- def test_get_progress_message_no_downloads(self):
327- """The progress message when no downloads are going on."""
328- self.aggregator.upload_done = 5
329- self.aggregator.upload_total = 10
330- self.aggregator.uploading_filename = FILENAME
331- self.aggregator.download_done = 0
332- self.aggregator.download_total = 0
333- self.aggregator.done_counter = 9
334- self.aggregator.total_counter = 20
335- percentage = int(100.0 * self.aggregator.done_counter /
336- self.aggregator.total_counter)
337- expected = (
338- aggregator.files_being_uploaded(
339- FILENAME, self.aggregator.upload_total) +
340- "\n" + aggregator.PROGRESS_COMPLETED) % {
341- 'percentage_completed': percentage}
342-
343- result = self.aggregator.get_progress_message()
344- self.assertEqual(expected, result)
345-
346- def test_get_progress_message_no_total(self):
347- """No progress message possible if total counter is zero."""
348- self.aggregator.total_counter = 0
349- self.assertRaises(AssertionError, self.aggregator.get_progress_message)
350-
351 def test_get_final_status_message(self):
352 """The final status message."""
353 done = (5, 10)
354@@ -1438,11 +1204,6 @@
355 result = self.aggregator.get_final_status_message()
356 self.assertEqual(expected, result)
357
358- def test_started_progress_bubble(self):
359- """The progress bubble is started."""
360- self.aggregator.restart_progress_bubble()
361- self.assertTrue(self.aggregator.progress_bubble.started)
362-
363 def test_queue_done_shows_bubble_when_downloads_happened(self):
364 """On queue done, show final bubble if downloads happened."""
365 fc = FakeCommand()
366@@ -1450,6 +1211,7 @@
367 self.status_frontend.download_finished(fc)
368 old_final_bubble = self.aggregator.final_status_bubble
369 self.aggregator.queue_done()
370+ self.aggregator.clock.advance(self.aggregator.finished_delay + 1)
371 self.assertTrue(old_final_bubble.shown)
372
373 def test_queue_done_shows_bubble_when_uploads_happened(self):
374@@ -1459,6 +1221,24 @@
375 self.status_frontend.upload_finished(fc)
376 old_final_bubble = self.aggregator.final_status_bubble
377 self.aggregator.queue_done()
378+ self.aggregator.clock.advance(self.aggregator.finished_delay + 1)
379+ self.assertTrue(old_final_bubble.shown)
380+
381+ def test_queue_done_shows_bubble_only_after_delay(self):
382+ """On queue_done, show final bubble only after a delay."""
383+ fc = FakeCommand()
384+ self.status_frontend.upload_started(fc)
385+ self.status_frontend.upload_finished(fc)
386+ old_final_bubble = self.aggregator.final_status_bubble
387+ self.aggregator.queue_done()
388+ self.assertFalse(old_final_bubble.shown)
389+ self.aggregator.clock.advance(self.aggregator.finished_delay - 1)
390+ self.assertFalse(old_final_bubble.shown)
391+ self.aggregator.queue_done()
392+ self.assertFalse(old_final_bubble.shown)
393+ self.aggregator.clock.advance(2)
394+ self.assertFalse(old_final_bubble.shown)
395+ self.aggregator.clock.advance(self.aggregator.finished_delay + 1)
396 self.assertTrue(old_final_bubble.shown)
397
398 def test_queue_done_does_not_show_bubble_when_no_transfers_happened(self):
399@@ -1474,6 +1254,7 @@
400 fc = FakeCommand()
401 self.status_frontend.upload_started(fc)
402 self.aggregator.queue_done()
403+ self.aggregator.clock.advance(self.aggregator.finished_delay + 1)
404 self.assertStatusReset()
405 self.assertEqual(0.0, self.aggregator.progress_bar.progress)
406 self.assertFalse(self.aggregator.progress_bar.visible)
407@@ -1524,7 +1305,6 @@
408 sf = aggregator.StatusFrontend(clock=clock)
409 sf.set_show_all_notifications(True)
410
411- clock.advance(aggregator.ProgressBubble.sleep_delay)
412 # the progress bar is not visible yet
413 self.assertFalse(sf.aggregator.progress_bar.visible)
414 sf.upload_started(upload)
415@@ -1548,25 +1328,12 @@
416 clock.advance(aggregator.FileDiscoveryUpdateState.updates_timeout -
417 aggregator.FileDiscoveryUpdateState.updates_delay)
418 sf.upload_finished(upload)
419- # the progress bubble has no notifications yet
420- self.assertEqual(None, sf.aggregator.progress_bubble.notification)
421- clock.advance(aggregator.ProgressBubble.sleep_delay)
422- # the progress bubble is shown
423- self.assertEqual(3, len(notifications_shown))
424 sf.upload_finished(download)
425 # the progress still is now 100%
426 self.assertEqual(1.0, sf.aggregator.progress_bar.progress)
427- # progress, but the progress bubble is not updated immediately
428- self.assertEqual(3, len(notifications_shown))
429- clock.advance(aggregator.ProgressBubble.sleep_delay)
430- # the progress bubble is updated after a delay
431- self.assertEqual(4, len(notifications_shown))
432 sf.queue_done()
433- # the final bubble is shown immediately
434- self.assertEqual(5, len(notifications_shown))
435- clock.advance(aggregator.ProgressBubble.sleep_delay * 2)
436- # no more notifications are shown
437- self.assertEqual(5, len(notifications_shown))
438+ clock.advance(sf.aggregator.finished_delay + 1)
439+ self.assertEqual(3, len(notifications_shown))
440
441 def test_all_together_now_off(self):
442 """Make all parts work together, but with notifications off."""
443@@ -1579,7 +1346,6 @@
444 sf = aggregator.StatusFrontend(clock=clock)
445 sf.set_show_all_notifications(False)
446
447- clock.advance(aggregator.ProgressBubble.sleep_delay)
448 # the progress bar is not visible yet
449 self.assertFalse(sf.aggregator.progress_bar.visible)
450 sf.upload_started(upload)
451@@ -1601,17 +1367,9 @@
452 clock.advance(aggregator.FileDiscoveryUpdateState.updates_timeout -
453 aggregator.FileDiscoveryUpdateState.updates_delay)
454 sf.upload_finished(upload)
455- # the progress bubble has no notifications yet
456- self.assertEqual(None, sf.aggregator.progress_bubble.notification)
457- clock.advance(aggregator.ProgressBubble.sleep_delay)
458- self.assertEqual(0, len(notifications_shown))
459 sf.upload_finished(download)
460 # the progress still is now 100%
461 self.assertEqual(1.0, sf.aggregator.progress_bar.progress)
462 self.assertEqual(0, len(notifications_shown))
463- clock.advance(aggregator.ProgressBubble.sleep_delay)
464- self.assertEqual(0, len(notifications_shown))
465 sf.queue_done()
466 self.assertEqual(0, len(notifications_shown))
467- clock.advance(aggregator.ProgressBubble.sleep_delay * 2)
468- self.assertEqual(0, len(notifications_shown))
469
470=== modified file 'tests/syncdaemon/test_status_listener.py'
471--- tests/syncdaemon/test_status_listener.py 2011-02-09 08:23:04 +0000
472+++ tests/syncdaemon/test_status_listener.py 2011-03-23 20:01:28 +0000
473@@ -250,32 +250,6 @@
474 self.assertIn(call, self.status_frontend.call_log)
475
476 @defer.inlineCallbacks
477- def test_queue_added_is_forwarded(self):
478- """A misc queue added event is forwarded."""
479- fake_command = object()
480-
481- d = defer.Deferred()
482- self._listen_for('SYS_QUEUE_ADDED', d.callback)
483- self.main.event_q.push('SYS_QUEUE_ADDED', command=fake_command)
484- yield d
485-
486- call = ("queue_added", (fake_command,), {})
487- self.assertIn(call, self.status_frontend.call_log)
488-
489- @defer.inlineCallbacks
490- def test_queue_removed_is_forwarded(self):
491- """A queue removed event is forwarded."""
492- fake_command = object()
493-
494- d = defer.Deferred()
495- self._listen_for('SYS_QUEUE_REMOVED', d.callback)
496- self.main.event_q.push('SYS_QUEUE_REMOVED', command=fake_command)
497- yield d
498-
499- call = ("queue_removed", (fake_command,), {})
500- self.assertIn(call, self.status_frontend.call_log)
501-
502- @defer.inlineCallbacks
503 def test_queue_done_is_forwarded(self):
504 """A queue done event is forwarded."""
505 d = defer.Deferred()
506
507=== modified file 'ubuntuone/status/aggregator.py'
508--- ubuntuone/status/aggregator.py 2011-03-22 17:20:50 +0000
509+++ ubuntuone/status/aggregator.py 2011-03-23 20:01:28 +0000
510@@ -465,17 +465,17 @@
511 def _popup(self):
512 """Display the notification."""
513 text = self.status_aggregator.get_discovery_message()
514- self.notification.send_notification(UBUNTUONE_TITLE, text)
515- self.status_aggregator.restart_progress_bubble()
516- logger.debug("notification shown: %s", text)
517+ if text:
518+ self.notification.send_notification(UBUNTUONE_TITLE, text)
519+ logger.debug("notification shown: %s", text)
520 self._change_state(FileDiscoveryUpdateState)
521
522 def _update(self):
523 """Update the notification."""
524 text = self.status_aggregator.get_discovery_message()
525- logger.debug("notification updated: %s", text)
526- self.status_aggregator.restart_progress_bubble()
527- self.notification.send_notification(UBUNTUONE_TITLE, text)
528+ if text:
529+ logger.debug("notification updated: %s", text)
530+ self.notification.send_notification(UBUNTUONE_TITLE, text)
531
532 def start_sleeping(self):
533 """Wait for 10 minutes before annoying again."""
534@@ -490,39 +490,6 @@
535 self.state.new_file_found()
536
537
538-class ProgressBubble(object):
539- """Show a notification for transfer progress."""
540-
541- sleep_delay = 600
542- notification = None
543- timer = None
544-
545- def __init__(self, status_aggregator, clock=reactor):
546- """Initialize this instance."""
547- self.status_aggregator = status_aggregator
548- self.clock = clock
549-
550- def restart(self):
551- """Start running the timer."""
552- self.cleanup()
553- self.timer = Timer(self.sleep_delay, clock=self.clock)
554- self.timer.addCallback(self._timeout)
555-
556- def _timeout(self, _):
557- """Show the bubble."""
558- self.notification = self.status_aggregator.get_notification()
559- text = self.status_aggregator.get_progress_message()
560- self.notification.send_notification(UBUNTUONE_TITLE, text)
561- self.restart()
562-
563- def cleanup(self):
564- """Cleanup this instance."""
565- if self.timer:
566- self.timer.cleanup()
567-
568- stop = cleanup
569-
570-
571 class ProgressBar(object):
572 """Update a progressbar no more than 10 times a second."""
573 pulsating = True
574@@ -624,15 +591,16 @@
575 """The status aggregator backend."""
576
577 file_discovery_bubble = None
578- progress_bubble = None
579 final_status_bubble = None
580
581 def __init__(self, clock=reactor):
582 """Initialize this instance."""
583 self.clock = clock
584 self.notification_switch = NotificationSwitch()
585+ self.queue_done_timer = None
586 self.reset()
587 self.progress_bar = ProgressBar(clock=self.clock)
588+ self.finished_delay = 10
589
590 def get_notification(self):
591 """Create a new toggleable notification object."""
592@@ -651,16 +619,14 @@
593 self.uploading_filename = ''
594 self.files_downloading = []
595 self.downloading_filename = ''
596+ if self.queue_done_timer is not None:
597+ self.queue_done_timer.cleanup()
598
599 if self.file_discovery_bubble:
600 self.file_discovery_bubble.cleanup()
601 self.file_discovery_bubble = FileDiscoveryBubble(self,
602 clock=self.clock)
603
604- if self.progress_bubble:
605- self.progress_bubble.cleanup()
606- self.progress_bubble = ProgressBubble(self, clock=self.clock)
607-
608 if self.final_status_bubble:
609 self.final_status_bubble.cleanup()
610 self.final_status_bubble = FinalStatusBubble(self)
611@@ -681,23 +647,6 @@
612 self.downloading_filename, files_downloading))
613 return "\n".join(lines)
614
615- def get_progress_message(self):
616- """Get some lines describing the progress."""
617- assert self.total_counter > 0
618- parts = []
619- upload_total = self.upload_total
620- if upload_total:
621- parts.append(files_being_uploaded(
622- self.uploading_filename, upload_total))
623- download_total = self.download_total
624- if download_total:
625- parts.append(files_being_downloaded(
626- self.downloading_filename, download_total))
627- progress_percentage = 100.0 * self.done_counter / self.total_counter
628- format_args = {"percentage_completed": int(progress_percentage)}
629- parts.append(PROGRESS_COMPLETED % format_args)
630- return "\n".join(parts)
631-
632 def get_final_status_message(self):
633 """Get some lines describing all we did."""
634 parts = []
635@@ -713,45 +662,48 @@
636 self.downloading_filename, download_done))
637 return "\n".join(parts)
638
639- def restart_progress_bubble(self):
640- """Restart the progress bubble."""
641- self.progress_bubble.restart()
642-
643- def queue_done(self):
644+ def _queue_done(self, _):
645 """Show final bubble and reset counters."""
646+ self.queue_done_timer.cleanup()
647+ self.queue_done_timer = None
648+ logger.debug("queue done callback fired")
649 if self.upload_done + self.download_done > 0:
650 self.final_status_bubble.show()
651 self.progress_bar.completed()
652 self.reset()
653
654- def misc_command_queued(self, command):
655- """A miscellaneous command was queued."""
656- self.total_counter += 1
657- logger.debug("queueing command (%d/%d): %s", self.done_counter,
658- self.total_counter, command.__class__.__name__)
659- self.update_progressbar()
660+ def queue_done(self):
661+ """Queue is finished."""
662+ if not self.total_counter:
663+ return
664+ if self.queue_done_timer is None:
665+ logger.debug("queue done callback added")
666+ self.queue_done_timer = Timer(
667+ self.finished_delay, clock=self.clock)
668+ self.queue_done_timer.addCallback(self._queue_done)
669+ return
670+ logger.debug("queue done callback reset")
671+ self.queue_done_timer.reset()
672
673 def update_progressbar(self):
674 """Update the counters of the progressbar."""
675 self.progress_bar.progress_made(self.done_counter, self.total_counter)
676
677- def misc_command_unqueued(self, command):
678- """A miscellaneous command was unqueued."""
679- self.done_counter += 1
680- logger.debug("unqueueing command (%d/%d): %s", self.done_counter,
681- self.total_counter, command.__class__.__name__)
682- self.update_progressbar()
683-
684 def download_started(self, command):
685 """A download just started."""
686+ if self.queue_done_timer is not None:
687+ self.queue_done_timer.reset()
688 self.files_downloading.append(command)
689 self.download_total += 1
690+ self.total_counter += 1
691 # pylint: disable=W0201
692 if not self.downloading_filename:
693 self.downloading_filename = self.files_downloading[0].path.split(
694 os.path.sep)[-1]
695 # pylint: enable=W0201
696- self.misc_command_queued(command)
697+ self.update_progressbar()
698+ logger.debug("queueing command (%d/%d): %s", self.done_counter,
699+ self.total_counter, command.__class__.__name__)
700 self.file_discovery_bubble.new_file_found()
701
702 def download_finished(self, command):
703@@ -759,18 +711,26 @@
704 if command in self.files_downloading:
705 self.files_downloading.remove(command)
706 self.download_done += 1
707- self.misc_command_unqueued(command)
708+ self.done_counter += 1
709+ logger.debug("unqueueing command (%d/%d): %s", self.done_counter,
710+ self.total_counter, command.__class__.__name__)
711+ self.update_progressbar()
712
713 def upload_started(self, command):
714 """An upload just started."""
715+ if self.queue_done_timer is not None:
716+ self.queue_done_timer.reset()
717 self.files_uploading.append(command)
718 self.upload_total += 1
719+ self.total_counter += 1
720 # pylint: disable=W0201
721 if not self.uploading_filename:
722 self.uploading_filename = self.files_uploading[0].path.split(
723 os.path.sep)[-1]
724 # pylint: enable=W0201
725- self.misc_command_queued(command)
726+ self.update_progressbar()
727+ logger.debug("queueing command (%d/%d): %s", self.done_counter,
728+ self.total_counter, command.__class__.__name__)
729 self.file_discovery_bubble.new_file_found()
730
731 def upload_finished(self, command):
732@@ -778,7 +738,10 @@
733 if command in self.files_uploading:
734 self.files_uploading.remove(command)
735 self.upload_done += 1
736- self.misc_command_unqueued(command)
737+ self.done_counter += 1
738+ logger.debug("unqueueing command (%d/%d): %s", self.done_counter,
739+ self.total_counter, command.__class__.__name__)
740+ self.update_progressbar()
741
742 def connection_lost(self):
743 """The connection to the server was lost."""
744@@ -826,14 +789,6 @@
745 """A file upload was unqueued."""
746 self.aggregator.upload_finished(command)
747
748- def queue_added(self, command):
749- """A command was added to the queue."""
750- self.aggregator.misc_command_queued(command)
751-
752- def queue_removed(self, command):
753- """A command was removed from the queue."""
754- self.aggregator.misc_command_unqueued(command)
755-
756 def queue_done(self):
757 """The queue is empty."""
758 self.aggregator.queue_done()
759
760=== modified file 'ubuntuone/syncdaemon/status_listener.py'
761--- ubuntuone/syncdaemon/status_listener.py 2011-02-09 08:23:04 +0000
762+++ ubuntuone/syncdaemon/status_listener.py 2011-03-23 20:01:28 +0000
763@@ -60,7 +60,7 @@
764 set_show_all_notifications)
765
766 def handle_AQ_CHANGE_PUBLIC_ACCESS_OK(self, share_id, node_id, is_public,
767- public_url):
768+ public_url):
769 """The status of a published resource changed."""
770 if is_public:
771 self.status_frontend.file_published(public_url)
772@@ -73,8 +73,6 @@
773 self.status_frontend.download_started(command)
774 elif isinstance(command, action_queue.Upload):
775 self.status_frontend.upload_started(command)
776- else:
777- self.status_frontend.queue_added(command)
778
779 def handle_SYS_QUEUE_REMOVED(self, command):
780 """A command has been removed from the queue."""
781@@ -82,8 +80,6 @@
782 self.status_frontend.download_finished(command)
783 elif isinstance(command, action_queue.Upload):
784 self.status_frontend.upload_finished(command)
785- else:
786- self.status_frontend.queue_removed(command)
787
788 def handle_SYS_QUEUE_DONE(self):
789 """The queue has finished processing everything."""

Subscribers

People subscribed via source and target branches