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

Proposed by Eric Casteleijn on 2011-03-23
Status: Merged
Approved by: Eric Casteleijn on 2011-03-23
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 on 2011-03-23
Natalia Bidart 2011-03-23 Approve on 2011-03-23
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.
review: Approve
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
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 on 2011-03-23

set the property before calling reset.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'tests/status/test_aggregator.py'
--- tests/status/test_aggregator.py 2011-03-22 16:59:19 +0000
+++ tests/status/test_aggregator.py 2011-03-23 20:01:28 +0000
@@ -200,7 +200,6 @@
200 """Initialize this instance."""200 """Initialize this instance."""
201 self.discovered = 0201 self.discovered = 0
202 self.completed = 0202 self.completed = 0
203 self.restart_progress_bubble_called = False
204 self.notification_switch = aggregator.NotificationSwitch()203 self.notification_switch = aggregator.NotificationSwitch()
205204
206 def get_discovery_message(self):205 def get_discovery_message(self):
@@ -226,10 +225,6 @@
226 """Return the final status message."""225 """Return the final status message."""
227 return "a lot of files completed."""226 return "a lot of files completed."""
228227
229 def restart_progress_bubble(self):
230 """Reset the progress bubble."""
231 self.restart_progress_bubble_called = True
232
233 def get_notification(self):228 def get_notification(self):
234 """Create a new toggleable notification object."""229 """Create a new toggleable notification object."""
235 return self.notification_switch.get_notification()230 return self.notification_switch.get_notification()
@@ -340,12 +335,6 @@
340 notification = (aggregator.UBUNTUONE_TITLE, message, None, False)335 notification = (aggregator.UBUNTUONE_TITLE, message, None, False)
341 self.assertIn(notification, self.get_notifications_shown())336 self.assertIn(notification, self.get_notifications_shown())
342337
343 def test_popup_resets_progress_bubble(self):
344 """The popup callback resets the progress bubble."""
345 self.bubble.new_file_found()
346 self.bubble._popup()
347 self.assertTrue(self.aggregator.restart_progress_bubble_called)
348
349 def test_notification_is_logged_in_debug(self):338 def test_notification_is_logged_in_debug(self):
350 """The notification is printed in the debug log."""339 """The notification is printed in the debug log."""
351 self.bubble.new_file_found()340 self.bubble.new_file_found()
@@ -430,14 +419,6 @@
430 self.clock.advance(self.updates_delay)419 self.clock.advance(self.updates_delay)
431 self.assertEqual(2, len(self.get_notifications_shown()))420 self.assertEqual(2, len(self.get_notifications_shown()))
432421
433 def test_update_resets_progress_bubble(self):
434 """The update callback resets the progress bubble."""
435 self.bubble.new_file_found()
436 self.bubble._popup()
437 self.bubble.new_file_found()
438 self.bubble._update()
439 self.assertTrue(self.aggregator.restart_progress_bubble_called)
440
441 def test_update_modifies_notification(self):422 def test_update_modifies_notification(self):
442 """The update callback updates notifications."""423 """The update callback updates notifications."""
443 self.bubble.new_file_found()424 self.bubble.new_file_found()
@@ -458,91 +439,6 @@
458 self.assertTrue(self.handler.check_debug(msg))439 self.assertTrue(self.handler.check_debug(msg))
459440
460441
461class ProgressBubbleTestCase(TestCase):
462 """Tests for the progress bubble."""
463
464 def setUp(self):
465 """Initialize this test instance."""
466 self.patch(aggregator, "ToggleableNotification",
467 FakeNotificationSingleton())
468 self.clock = PatchedClock()
469 self.aggregator = FakeStatusAggregator(clock=self.clock)
470 self.bubble = aggregator.ProgressBubble(self.aggregator,
471 clock=self.clock)
472 self.addCleanup(self.bubble.cleanup)
473 self.smaller_delay = aggregator.ProgressBubble.sleep_delay * 0.8
474 self.right_delay = aggregator.ProgressBubble.sleep_delay
475 self.longer_delay = aggregator.ProgressBubble.sleep_delay * 1.2
476
477 def test_is_created_successfully(self):
478 """The progress bubble is created and idle."""
479 self.assertEqual(None, self.bubble.timer)
480
481 def test_restart_creates_timer(self):
482 """Restarting creates a timer."""
483 self.bubble.restart()
484 self.assertNotEqual(None, self.bubble.timer)
485
486 def test_not_shown_initially(self):
487 """The bubble is not shown initially."""
488 self.bubble.restart()
489 self.assertEqual(None, self.bubble.notification)
490
491 def test_not_shown_immediately(self):
492 """The bubble is not shown immediately."""
493 self.bubble.restart()
494 self.clock.advance(self.smaller_delay)
495 self.assertEqual(None, self.bubble.notification)
496
497 def test_shown_after_delay(self):
498 """The bubble is shown after the standard delay."""
499 self.bubble.restart()
500 self.clock.advance(self.longer_delay)
501 self.assertEqual(1, len(self.bubble.notification.notifications_shown))
502
503 def test_not_shown_if_restarted(self):
504 """The delay is adjusted when restarting."""
505 self.bubble.restart()
506 self.clock.advance(self.smaller_delay)
507 self.bubble.restart()
508 self.clock.advance(self.smaller_delay)
509 self.assertEqual(None, self.bubble.notification)
510
511 def test_delay_reached_after_restart(self):
512 """The timeout is still reached after a restart."""
513 self.bubble.restart()
514 self.clock.advance(self.smaller_delay)
515 self.bubble.restart()
516 self.clock.advance(self.longer_delay)
517 self.assertEqual(1, len(self.bubble.notification.notifications_shown))
518
519 def test_can_be_stopped(self):
520 """The timeout can be stopped."""
521 self.bubble.restart()
522 self.clock.advance(self.smaller_delay)
523 self.bubble.stop()
524 self.clock.advance(self.longer_delay)
525 self.assertEqual(None, self.bubble.notification)
526
527 def test_delay_reached_after_stopping_then_restarting(self):
528 """The timeout is still reached after a stop followed by a restart."""
529 self.bubble.restart()
530 self.clock.advance(self.smaller_delay)
531 self.bubble.stop()
532 self.clock.advance(self.longer_delay)
533 self.bubble.restart()
534 self.clock.advance(self.longer_delay)
535 self.assertEqual(1, len(self.bubble.notification.notifications_shown))
536
537 def test_restarts_automatically(self):
538 """The timer is restarted automatically."""
539 self.bubble.restart()
540 self.clock.advance(self.right_delay)
541 self.assertEqual(1, len(self.bubble.notification.notifications_shown))
542 self.clock.advance(self.right_delay)
543 self.assertEqual(2, len(self.bubble.notification.notifications_shown))
544
545
546class FinalBubbleTestCase(TestCase):442class FinalBubbleTestCase(TestCase):
547 """Test for the final status notification bubble."""443 """Test for the final status notification bubble."""
548444
@@ -788,14 +684,6 @@
788 """The queue completed all operations."""684 """The queue completed all operations."""
789 self.queued_commands.clear()685 self.queued_commands.clear()
790686
791 def misc_command_queued(self, command):
792 """A new command was queued."""
793 self.queued_commands.add(command)
794
795 def misc_command_unqueued(self, command):
796 """A new command was unqueued."""
797 self.queued_commands.discard(command)
798
799 def get_notification(self):687 def get_notification(self):
800 """Create a new toggleable notification object."""688 """Create a new toggleable notification object."""
801 return self.notification_switch.get_notification()689 return self.notification_switch.get_notification()
@@ -803,24 +691,24 @@
803 def download_started(self, command):691 def download_started(self, command):
804 """A download just started."""692 """A download just started."""
805 self.files_downloading.append(command)693 self.files_downloading.append(command)
806 self.misc_command_queued(command)694 self.queued_commands.add(command)
807695
808 def download_finished(self, command):696 def download_finished(self, command):
809 """A download just finished."""697 """A download just finished."""
810 if command in self.files_downloading:698 if command in self.files_downloading:
811 self.files_downloading.remove(command)699 self.files_downloading.remove(command)
812 self.misc_command_unqueued(command)700 self.queued_commands.discard(command)
813701
814 def upload_started(self, command):702 def upload_started(self, command):
815 """An upload just started."""703 """An upload just started."""
816 self.files_uploading.append(command)704 self.files_uploading.append(command)
817 self.misc_command_queued(command)705 self.queued_commands.add(command)
818706
819 def upload_finished(self, command):707 def upload_finished(self, command):
820 """An upload just finished."""708 """An upload just finished."""
821 if command in self.files_uploading:709 if command in self.files_uploading:
822 self.files_uploading.remove(command)710 self.files_uploading.remove(command)
823 self.misc_command_unqueued(command)711 self.queued_commands.discard(command)
824712
825 def connection_made(self):713 def connection_made(self):
826 """The client made the connection to the server."""714 """The client made the connection to the server."""
@@ -914,21 +802,6 @@
914 qc = self.status_frontend.aggregator.queued_commands802 qc = self.status_frontend.aggregator.queued_commands
915 self.assertNotIn(fake_command, qc)803 self.assertNotIn(fake_command, qc)
916804
917 def test_queue_added(self):
918 """A command was added to the queue."""
919 fake_command = FakeCommand()
920 self.listener.handle_SYS_QUEUE_ADDED(fake_command)
921 qc = self.status_frontend.aggregator.queued_commands
922 self.assertIn(fake_command, qc)
923
924 def test_queue_removed(self):
925 """A command has finished and is removed from the queue."""
926 fake_command = FakeCommand()
927 self.listener.handle_SYS_QUEUE_ADDED(fake_command)
928 self.listener.handle_SYS_QUEUE_REMOVED(fake_command)
929 qc = self.status_frontend.aggregator.queued_commands
930 self.assertNotIn(fake_command, qc)
931
932 def test_queue_done(self):805 def test_queue_done(self):
933 """The queue is empty."""806 """The queue is empty."""
934 fake_command = FakeCommand()807 fake_command = FakeCommand()
@@ -1161,27 +1034,6 @@
1161 """Cleanup this instance."""1034 """Cleanup this instance."""
11621035
11631036
1164class FakeProgressBubble(object):
1165 """A fake ProgressBubble object."""
1166
1167 started = False
1168 stopped = False
1169
1170 def __init__(self, status_aggregator, clock=None):
1171 """Initialize this instance."""
1172 self.status_aggregator = status_aggregator
1173
1174 def cleanup(self):
1175 """Cleanup this instance."""
1176
1177 def restart(self):
1178 """Start this bubble waiting."""
1179 self.started = True
1180
1181 def stop(self):
1182 """Make this bubble stop."""
1183
1184
1185class FakeFinalBubble(object):1037class FakeFinalBubble(object):
1186 """A fake FinalStatusBubble."""1038 """A fake FinalStatusBubble."""
11871039
@@ -1206,15 +1058,14 @@
1206 """Initialize this test instance."""1058 """Initialize this test instance."""
1207 self.patch(aggregator, "FileDiscoveryBubble",1059 self.patch(aggregator, "FileDiscoveryBubble",
1208 FakeFileDiscoveryBubble)1060 FakeFileDiscoveryBubble)
1209 self.patch(aggregator, "ProgressBubble",
1210 FakeProgressBubble)
1211 self.patch(aggregator, "FinalStatusBubble",1061 self.patch(aggregator, "FinalStatusBubble",
1212 FakeFinalBubble)1062 FakeFinalBubble)
1213 self.patch(aggregator, "ToggleableNotification",1063 self.patch(aggregator, "ToggleableNotification",
1214 FakeNotificationSingleton())1064 FakeNotificationSingleton())
1215 self.patch(aggregator, "UbuntuOneLauncher", FakeLauncher)1065 self.patch(aggregator, "UbuntuOneLauncher", FakeLauncher)
1216 self.patch(aggregator.session, "Inhibitor", FakeInhibitor)1066 self.patch(aggregator.session, "Inhibitor", FakeInhibitor)
1217 self.status_frontend = aggregator.StatusFrontend()1067 clock = PatchedClock()
1068 self.status_frontend = aggregator.StatusFrontend(clock=clock)
1218 self.aggregator = self.status_frontend.aggregator1069 self.aggregator = self.status_frontend.aggregator
1219 self.fake_bubble = self.aggregator.file_discovery_bubble1070 self.fake_bubble = self.aggregator.file_discovery_bubble
12201071
@@ -1253,21 +1104,6 @@
1253 """Test that the counters start at zero."""1104 """Test that the counters start at zero."""
1254 self.assertStatusReset()1105 self.assertStatusReset()
12551106
1256 def test_misc_command_queue(self):
1257 """Test that a misc command was queued."""
1258 fc = FakeCommand()
1259 self.status_frontend.queue_added(fc)
1260 self.assertMiscCommandQueued(fc)
1261 self.assertEqual(0, self.aggregator.progress_bar.progress)
1262
1263 def test_misc_command_unqueue(self):
1264 """Test that a misc command was unqueued."""
1265 fc = FakeCommand()
1266 self.status_frontend.queue_added(fc)
1267 self.status_frontend.queue_removed(fc)
1268 self.assertMiscCommandUnqueued(fc)
1269 self.assertEqual(1.0, self.aggregator.progress_bar.progress)
1270
1271 def test_file_download_started(self):1107 def test_file_download_started(self):
1272 """Test that a file has started download."""1108 """Test that a file has started download."""
1273 fc = FakeCommand(path='testfile.txt')1109 fc = FakeCommand(path='testfile.txt')
@@ -1323,76 +1159,6 @@
1323 result = self.aggregator.get_discovery_message()1159 result = self.aggregator.get_discovery_message()
1324 self.assertEqual(expected, result)1160 self.assertEqual(expected, result)
13251161
1326 def test_get_progress_message(self):
1327 """Test the message that's shown on the progress bubble."""
1328 self.aggregator.upload_done = 5
1329 self.aggregator.upload_total = 10
1330 self.aggregator.uploading_filename = FILENAME
1331 self.aggregator.download_done = 3
1332 self.aggregator.download_total = 8
1333 self.aggregator.downloading_filename = FILENAME2
1334 self.aggregator.done_counter = 9
1335 self.aggregator.total_counter = 20
1336 percentage = int(100.0 * self.aggregator.done_counter /
1337 self.aggregator.total_counter)
1338
1339 expected = (
1340 aggregator.files_being_uploaded(
1341 FILENAME, self.aggregator.upload_total) + "\n" +
1342 aggregator.files_being_downloaded(
1343 FILENAME2, self.aggregator.download_total) + "\n" +
1344 aggregator.PROGRESS_COMPLETED) % {
1345 'percentage_completed': percentage}
1346
1347 result = self.aggregator.get_progress_message()
1348 self.assertEqual(expected, result)
1349
1350 def test_get_progress_message_no_uploads(self):
1351 """The progress message when no uploads are going on."""
1352
1353 self.aggregator.upload_done = 0
1354 self.aggregator.upload_total = 0
1355 self.aggregator.downloading_filename = FILENAME
1356 self.aggregator.download_done = 3
1357 self.aggregator.download_total = 8
1358 self.aggregator.done_counter = 9
1359 self.aggregator.total_counter = 20
1360 percentage = int(100.0 * self.aggregator.done_counter /
1361 self.aggregator.total_counter)
1362 expected = (
1363 aggregator.files_being_downloaded(
1364 FILENAME, self.aggregator.download_total) + "\n" +
1365 aggregator.PROGRESS_COMPLETED) % {
1366 'percentage_completed': percentage}
1367
1368 result = self.aggregator.get_progress_message()
1369 self.assertEqual(expected, result)
1370
1371 def test_get_progress_message_no_downloads(self):
1372 """The progress message when no downloads are going on."""
1373 self.aggregator.upload_done = 5
1374 self.aggregator.upload_total = 10
1375 self.aggregator.uploading_filename = FILENAME
1376 self.aggregator.download_done = 0
1377 self.aggregator.download_total = 0
1378 self.aggregator.done_counter = 9
1379 self.aggregator.total_counter = 20
1380 percentage = int(100.0 * self.aggregator.done_counter /
1381 self.aggregator.total_counter)
1382 expected = (
1383 aggregator.files_being_uploaded(
1384 FILENAME, self.aggregator.upload_total) +
1385 "\n" + aggregator.PROGRESS_COMPLETED) % {
1386 'percentage_completed': percentage}
1387
1388 result = self.aggregator.get_progress_message()
1389 self.assertEqual(expected, result)
1390
1391 def test_get_progress_message_no_total(self):
1392 """No progress message possible if total counter is zero."""
1393 self.aggregator.total_counter = 0
1394 self.assertRaises(AssertionError, self.aggregator.get_progress_message)
1395
1396 def test_get_final_status_message(self):1162 def test_get_final_status_message(self):
1397 """The final status message."""1163 """The final status message."""
1398 done = (5, 10)1164 done = (5, 10)
@@ -1438,11 +1204,6 @@
1438 result = self.aggregator.get_final_status_message()1204 result = self.aggregator.get_final_status_message()
1439 self.assertEqual(expected, result)1205 self.assertEqual(expected, result)
14401206
1441 def test_started_progress_bubble(self):
1442 """The progress bubble is started."""
1443 self.aggregator.restart_progress_bubble()
1444 self.assertTrue(self.aggregator.progress_bubble.started)
1445
1446 def test_queue_done_shows_bubble_when_downloads_happened(self):1207 def test_queue_done_shows_bubble_when_downloads_happened(self):
1447 """On queue done, show final bubble if downloads happened."""1208 """On queue done, show final bubble if downloads happened."""
1448 fc = FakeCommand()1209 fc = FakeCommand()
@@ -1450,6 +1211,7 @@
1450 self.status_frontend.download_finished(fc)1211 self.status_frontend.download_finished(fc)
1451 old_final_bubble = self.aggregator.final_status_bubble1212 old_final_bubble = self.aggregator.final_status_bubble
1452 self.aggregator.queue_done()1213 self.aggregator.queue_done()
1214 self.aggregator.clock.advance(self.aggregator.finished_delay + 1)
1453 self.assertTrue(old_final_bubble.shown)1215 self.assertTrue(old_final_bubble.shown)
14541216
1455 def test_queue_done_shows_bubble_when_uploads_happened(self):1217 def test_queue_done_shows_bubble_when_uploads_happened(self):
@@ -1459,6 +1221,24 @@
1459 self.status_frontend.upload_finished(fc)1221 self.status_frontend.upload_finished(fc)
1460 old_final_bubble = self.aggregator.final_status_bubble1222 old_final_bubble = self.aggregator.final_status_bubble
1461 self.aggregator.queue_done()1223 self.aggregator.queue_done()
1224 self.aggregator.clock.advance(self.aggregator.finished_delay + 1)
1225 self.assertTrue(old_final_bubble.shown)
1226
1227 def test_queue_done_shows_bubble_only_after_delay(self):
1228 """On queue_done, show final bubble only after a delay."""
1229 fc = FakeCommand()
1230 self.status_frontend.upload_started(fc)
1231 self.status_frontend.upload_finished(fc)
1232 old_final_bubble = self.aggregator.final_status_bubble
1233 self.aggregator.queue_done()
1234 self.assertFalse(old_final_bubble.shown)
1235 self.aggregator.clock.advance(self.aggregator.finished_delay - 1)
1236 self.assertFalse(old_final_bubble.shown)
1237 self.aggregator.queue_done()
1238 self.assertFalse(old_final_bubble.shown)
1239 self.aggregator.clock.advance(2)
1240 self.assertFalse(old_final_bubble.shown)
1241 self.aggregator.clock.advance(self.aggregator.finished_delay + 1)
1462 self.assertTrue(old_final_bubble.shown)1242 self.assertTrue(old_final_bubble.shown)
14631243
1464 def test_queue_done_does_not_show_bubble_when_no_transfers_happened(self):1244 def test_queue_done_does_not_show_bubble_when_no_transfers_happened(self):
@@ -1474,6 +1254,7 @@
1474 fc = FakeCommand()1254 fc = FakeCommand()
1475 self.status_frontend.upload_started(fc)1255 self.status_frontend.upload_started(fc)
1476 self.aggregator.queue_done()1256 self.aggregator.queue_done()
1257 self.aggregator.clock.advance(self.aggregator.finished_delay + 1)
1477 self.assertStatusReset()1258 self.assertStatusReset()
1478 self.assertEqual(0.0, self.aggregator.progress_bar.progress)1259 self.assertEqual(0.0, self.aggregator.progress_bar.progress)
1479 self.assertFalse(self.aggregator.progress_bar.visible)1260 self.assertFalse(self.aggregator.progress_bar.visible)
@@ -1524,7 +1305,6 @@
1524 sf = aggregator.StatusFrontend(clock=clock)1305 sf = aggregator.StatusFrontend(clock=clock)
1525 sf.set_show_all_notifications(True)1306 sf.set_show_all_notifications(True)
15261307
1527 clock.advance(aggregator.ProgressBubble.sleep_delay)
1528 # the progress bar is not visible yet1308 # the progress bar is not visible yet
1529 self.assertFalse(sf.aggregator.progress_bar.visible)1309 self.assertFalse(sf.aggregator.progress_bar.visible)
1530 sf.upload_started(upload)1310 sf.upload_started(upload)
@@ -1548,25 +1328,12 @@
1548 clock.advance(aggregator.FileDiscoveryUpdateState.updates_timeout -1328 clock.advance(aggregator.FileDiscoveryUpdateState.updates_timeout -
1549 aggregator.FileDiscoveryUpdateState.updates_delay)1329 aggregator.FileDiscoveryUpdateState.updates_delay)
1550 sf.upload_finished(upload)1330 sf.upload_finished(upload)
1551 # the progress bubble has no notifications yet
1552 self.assertEqual(None, sf.aggregator.progress_bubble.notification)
1553 clock.advance(aggregator.ProgressBubble.sleep_delay)
1554 # the progress bubble is shown
1555 self.assertEqual(3, len(notifications_shown))
1556 sf.upload_finished(download)1331 sf.upload_finished(download)
1557 # the progress still is now 100%1332 # the progress still is now 100%
1558 self.assertEqual(1.0, sf.aggregator.progress_bar.progress)1333 self.assertEqual(1.0, sf.aggregator.progress_bar.progress)
1559 # progress, but the progress bubble is not updated immediately
1560 self.assertEqual(3, len(notifications_shown))
1561 clock.advance(aggregator.ProgressBubble.sleep_delay)
1562 # the progress bubble is updated after a delay
1563 self.assertEqual(4, len(notifications_shown))
1564 sf.queue_done()1334 sf.queue_done()
1565 # the final bubble is shown immediately1335 clock.advance(sf.aggregator.finished_delay + 1)
1566 self.assertEqual(5, len(notifications_shown))1336 self.assertEqual(3, len(notifications_shown))
1567 clock.advance(aggregator.ProgressBubble.sleep_delay * 2)
1568 # no more notifications are shown
1569 self.assertEqual(5, len(notifications_shown))
15701337
1571 def test_all_together_now_off(self):1338 def test_all_together_now_off(self):
1572 """Make all parts work together, but with notifications off."""1339 """Make all parts work together, but with notifications off."""
@@ -1579,7 +1346,6 @@
1579 sf = aggregator.StatusFrontend(clock=clock)1346 sf = aggregator.StatusFrontend(clock=clock)
1580 sf.set_show_all_notifications(False)1347 sf.set_show_all_notifications(False)
15811348
1582 clock.advance(aggregator.ProgressBubble.sleep_delay)
1583 # the progress bar is not visible yet1349 # the progress bar is not visible yet
1584 self.assertFalse(sf.aggregator.progress_bar.visible)1350 self.assertFalse(sf.aggregator.progress_bar.visible)
1585 sf.upload_started(upload)1351 sf.upload_started(upload)
@@ -1601,17 +1367,9 @@
1601 clock.advance(aggregator.FileDiscoveryUpdateState.updates_timeout -1367 clock.advance(aggregator.FileDiscoveryUpdateState.updates_timeout -
1602 aggregator.FileDiscoveryUpdateState.updates_delay)1368 aggregator.FileDiscoveryUpdateState.updates_delay)
1603 sf.upload_finished(upload)1369 sf.upload_finished(upload)
1604 # the progress bubble has no notifications yet
1605 self.assertEqual(None, sf.aggregator.progress_bubble.notification)
1606 clock.advance(aggregator.ProgressBubble.sleep_delay)
1607 self.assertEqual(0, len(notifications_shown))
1608 sf.upload_finished(download)1370 sf.upload_finished(download)
1609 # the progress still is now 100%1371 # the progress still is now 100%
1610 self.assertEqual(1.0, sf.aggregator.progress_bar.progress)1372 self.assertEqual(1.0, sf.aggregator.progress_bar.progress)
1611 self.assertEqual(0, len(notifications_shown))1373 self.assertEqual(0, len(notifications_shown))
1612 clock.advance(aggregator.ProgressBubble.sleep_delay)
1613 self.assertEqual(0, len(notifications_shown))
1614 sf.queue_done()1374 sf.queue_done()
1615 self.assertEqual(0, len(notifications_shown))1375 self.assertEqual(0, len(notifications_shown))
1616 clock.advance(aggregator.ProgressBubble.sleep_delay * 2)
1617 self.assertEqual(0, len(notifications_shown))
16181376
=== modified file 'tests/syncdaemon/test_status_listener.py'
--- tests/syncdaemon/test_status_listener.py 2011-02-09 08:23:04 +0000
+++ tests/syncdaemon/test_status_listener.py 2011-03-23 20:01:28 +0000
@@ -250,32 +250,6 @@
250 self.assertIn(call, self.status_frontend.call_log)250 self.assertIn(call, self.status_frontend.call_log)
251251
252 @defer.inlineCallbacks252 @defer.inlineCallbacks
253 def test_queue_added_is_forwarded(self):
254 """A misc queue added event is forwarded."""
255 fake_command = object()
256
257 d = defer.Deferred()
258 self._listen_for('SYS_QUEUE_ADDED', d.callback)
259 self.main.event_q.push('SYS_QUEUE_ADDED', command=fake_command)
260 yield d
261
262 call = ("queue_added", (fake_command,), {})
263 self.assertIn(call, self.status_frontend.call_log)
264
265 @defer.inlineCallbacks
266 def test_queue_removed_is_forwarded(self):
267 """A queue removed event is forwarded."""
268 fake_command = object()
269
270 d = defer.Deferred()
271 self._listen_for('SYS_QUEUE_REMOVED', d.callback)
272 self.main.event_q.push('SYS_QUEUE_REMOVED', command=fake_command)
273 yield d
274
275 call = ("queue_removed", (fake_command,), {})
276 self.assertIn(call, self.status_frontend.call_log)
277
278 @defer.inlineCallbacks
279 def test_queue_done_is_forwarded(self):253 def test_queue_done_is_forwarded(self):
280 """A queue done event is forwarded."""254 """A queue done event is forwarded."""
281 d = defer.Deferred()255 d = defer.Deferred()
282256
=== modified file 'ubuntuone/status/aggregator.py'
--- ubuntuone/status/aggregator.py 2011-03-22 17:20:50 +0000
+++ ubuntuone/status/aggregator.py 2011-03-23 20:01:28 +0000
@@ -465,17 +465,17 @@
465 def _popup(self):465 def _popup(self):
466 """Display the notification."""466 """Display the notification."""
467 text = self.status_aggregator.get_discovery_message()467 text = self.status_aggregator.get_discovery_message()
468 self.notification.send_notification(UBUNTUONE_TITLE, text)468 if text:
469 self.status_aggregator.restart_progress_bubble()469 self.notification.send_notification(UBUNTUONE_TITLE, text)
470 logger.debug("notification shown: %s", text)470 logger.debug("notification shown: %s", text)
471 self._change_state(FileDiscoveryUpdateState)471 self._change_state(FileDiscoveryUpdateState)
472472
473 def _update(self):473 def _update(self):
474 """Update the notification."""474 """Update the notification."""
475 text = self.status_aggregator.get_discovery_message()475 text = self.status_aggregator.get_discovery_message()
476 logger.debug("notification updated: %s", text)476 if text:
477 self.status_aggregator.restart_progress_bubble()477 logger.debug("notification updated: %s", text)
478 self.notification.send_notification(UBUNTUONE_TITLE, text)478 self.notification.send_notification(UBUNTUONE_TITLE, text)
479479
480 def start_sleeping(self):480 def start_sleeping(self):
481 """Wait for 10 minutes before annoying again."""481 """Wait for 10 minutes before annoying again."""
@@ -490,39 +490,6 @@
490 self.state.new_file_found()490 self.state.new_file_found()
491491
492492
493class ProgressBubble(object):
494 """Show a notification for transfer progress."""
495
496 sleep_delay = 600
497 notification = None
498 timer = None
499
500 def __init__(self, status_aggregator, clock=reactor):
501 """Initialize this instance."""
502 self.status_aggregator = status_aggregator
503 self.clock = clock
504
505 def restart(self):
506 """Start running the timer."""
507 self.cleanup()
508 self.timer = Timer(self.sleep_delay, clock=self.clock)
509 self.timer.addCallback(self._timeout)
510
511 def _timeout(self, _):
512 """Show the bubble."""
513 self.notification = self.status_aggregator.get_notification()
514 text = self.status_aggregator.get_progress_message()
515 self.notification.send_notification(UBUNTUONE_TITLE, text)
516 self.restart()
517
518 def cleanup(self):
519 """Cleanup this instance."""
520 if self.timer:
521 self.timer.cleanup()
522
523 stop = cleanup
524
525
526class ProgressBar(object):493class ProgressBar(object):
527 """Update a progressbar no more than 10 times a second."""494 """Update a progressbar no more than 10 times a second."""
528 pulsating = True495 pulsating = True
@@ -624,15 +591,16 @@
624 """The status aggregator backend."""591 """The status aggregator backend."""
625592
626 file_discovery_bubble = None593 file_discovery_bubble = None
627 progress_bubble = None
628 final_status_bubble = None594 final_status_bubble = None
629595
630 def __init__(self, clock=reactor):596 def __init__(self, clock=reactor):
631 """Initialize this instance."""597 """Initialize this instance."""
632 self.clock = clock598 self.clock = clock
633 self.notification_switch = NotificationSwitch()599 self.notification_switch = NotificationSwitch()
600 self.queue_done_timer = None
634 self.reset()601 self.reset()
635 self.progress_bar = ProgressBar(clock=self.clock)602 self.progress_bar = ProgressBar(clock=self.clock)
603 self.finished_delay = 10
636604
637 def get_notification(self):605 def get_notification(self):
638 """Create a new toggleable notification object."""606 """Create a new toggleable notification object."""
@@ -651,16 +619,14 @@
651 self.uploading_filename = ''619 self.uploading_filename = ''
652 self.files_downloading = []620 self.files_downloading = []
653 self.downloading_filename = ''621 self.downloading_filename = ''
622 if self.queue_done_timer is not None:
623 self.queue_done_timer.cleanup()
654624
655 if self.file_discovery_bubble:625 if self.file_discovery_bubble:
656 self.file_discovery_bubble.cleanup()626 self.file_discovery_bubble.cleanup()
657 self.file_discovery_bubble = FileDiscoveryBubble(self,627 self.file_discovery_bubble = FileDiscoveryBubble(self,
658 clock=self.clock)628 clock=self.clock)
659629
660 if self.progress_bubble:
661 self.progress_bubble.cleanup()
662 self.progress_bubble = ProgressBubble(self, clock=self.clock)
663
664 if self.final_status_bubble:630 if self.final_status_bubble:
665 self.final_status_bubble.cleanup()631 self.final_status_bubble.cleanup()
666 self.final_status_bubble = FinalStatusBubble(self)632 self.final_status_bubble = FinalStatusBubble(self)
@@ -681,23 +647,6 @@
681 self.downloading_filename, files_downloading))647 self.downloading_filename, files_downloading))
682 return "\n".join(lines)648 return "\n".join(lines)
683649
684 def get_progress_message(self):
685 """Get some lines describing the progress."""
686 assert self.total_counter > 0
687 parts = []
688 upload_total = self.upload_total
689 if upload_total:
690 parts.append(files_being_uploaded(
691 self.uploading_filename, upload_total))
692 download_total = self.download_total
693 if download_total:
694 parts.append(files_being_downloaded(
695 self.downloading_filename, download_total))
696 progress_percentage = 100.0 * self.done_counter / self.total_counter
697 format_args = {"percentage_completed": int(progress_percentage)}
698 parts.append(PROGRESS_COMPLETED % format_args)
699 return "\n".join(parts)
700
701 def get_final_status_message(self):650 def get_final_status_message(self):
702 """Get some lines describing all we did."""651 """Get some lines describing all we did."""
703 parts = []652 parts = []
@@ -713,45 +662,48 @@
713 self.downloading_filename, download_done))662 self.downloading_filename, download_done))
714 return "\n".join(parts)663 return "\n".join(parts)
715664
716 def restart_progress_bubble(self):665 def _queue_done(self, _):
717 """Restart the progress bubble."""
718 self.progress_bubble.restart()
719
720 def queue_done(self):
721 """Show final bubble and reset counters."""666 """Show final bubble and reset counters."""
667 self.queue_done_timer.cleanup()
668 self.queue_done_timer = None
669 logger.debug("queue done callback fired")
722 if self.upload_done + self.download_done > 0:670 if self.upload_done + self.download_done > 0:
723 self.final_status_bubble.show()671 self.final_status_bubble.show()
724 self.progress_bar.completed()672 self.progress_bar.completed()
725 self.reset()673 self.reset()
726674
727 def misc_command_queued(self, command):675 def queue_done(self):
728 """A miscellaneous command was queued."""676 """Queue is finished."""
729 self.total_counter += 1677 if not self.total_counter:
730 logger.debug("queueing command (%d/%d): %s", self.done_counter,678 return
731 self.total_counter, command.__class__.__name__)679 if self.queue_done_timer is None:
732 self.update_progressbar()680 logger.debug("queue done callback added")
681 self.queue_done_timer = Timer(
682 self.finished_delay, clock=self.clock)
683 self.queue_done_timer.addCallback(self._queue_done)
684 return
685 logger.debug("queue done callback reset")
686 self.queue_done_timer.reset()
733687
734 def update_progressbar(self):688 def update_progressbar(self):
735 """Update the counters of the progressbar."""689 """Update the counters of the progressbar."""
736 self.progress_bar.progress_made(self.done_counter, self.total_counter)690 self.progress_bar.progress_made(self.done_counter, self.total_counter)
737691
738 def misc_command_unqueued(self, command):
739 """A miscellaneous command was unqueued."""
740 self.done_counter += 1
741 logger.debug("unqueueing command (%d/%d): %s", self.done_counter,
742 self.total_counter, command.__class__.__name__)
743 self.update_progressbar()
744
745 def download_started(self, command):692 def download_started(self, command):
746 """A download just started."""693 """A download just started."""
694 if self.queue_done_timer is not None:
695 self.queue_done_timer.reset()
747 self.files_downloading.append(command)696 self.files_downloading.append(command)
748 self.download_total += 1697 self.download_total += 1
698 self.total_counter += 1
749 # pylint: disable=W0201699 # pylint: disable=W0201
750 if not self.downloading_filename:700 if not self.downloading_filename:
751 self.downloading_filename = self.files_downloading[0].path.split(701 self.downloading_filename = self.files_downloading[0].path.split(
752 os.path.sep)[-1]702 os.path.sep)[-1]
753 # pylint: enable=W0201703 # pylint: enable=W0201
754 self.misc_command_queued(command)704 self.update_progressbar()
705 logger.debug("queueing command (%d/%d): %s", self.done_counter,
706 self.total_counter, command.__class__.__name__)
755 self.file_discovery_bubble.new_file_found()707 self.file_discovery_bubble.new_file_found()
756708
757 def download_finished(self, command):709 def download_finished(self, command):
@@ -759,18 +711,26 @@
759 if command in self.files_downloading:711 if command in self.files_downloading:
760 self.files_downloading.remove(command)712 self.files_downloading.remove(command)
761 self.download_done += 1713 self.download_done += 1
762 self.misc_command_unqueued(command)714 self.done_counter += 1
715 logger.debug("unqueueing command (%d/%d): %s", self.done_counter,
716 self.total_counter, command.__class__.__name__)
717 self.update_progressbar()
763718
764 def upload_started(self, command):719 def upload_started(self, command):
765 """An upload just started."""720 """An upload just started."""
721 if self.queue_done_timer is not None:
722 self.queue_done_timer.reset()
766 self.files_uploading.append(command)723 self.files_uploading.append(command)
767 self.upload_total += 1724 self.upload_total += 1
725 self.total_counter += 1
768 # pylint: disable=W0201726 # pylint: disable=W0201
769 if not self.uploading_filename:727 if not self.uploading_filename:
770 self.uploading_filename = self.files_uploading[0].path.split(728 self.uploading_filename = self.files_uploading[0].path.split(
771 os.path.sep)[-1]729 os.path.sep)[-1]
772 # pylint: enable=W0201730 # pylint: enable=W0201
773 self.misc_command_queued(command)731 self.update_progressbar()
732 logger.debug("queueing command (%d/%d): %s", self.done_counter,
733 self.total_counter, command.__class__.__name__)
774 self.file_discovery_bubble.new_file_found()734 self.file_discovery_bubble.new_file_found()
775735
776 def upload_finished(self, command):736 def upload_finished(self, command):
@@ -778,7 +738,10 @@
778 if command in self.files_uploading:738 if command in self.files_uploading:
779 self.files_uploading.remove(command)739 self.files_uploading.remove(command)
780 self.upload_done += 1740 self.upload_done += 1
781 self.misc_command_unqueued(command)741 self.done_counter += 1
742 logger.debug("unqueueing command (%d/%d): %s", self.done_counter,
743 self.total_counter, command.__class__.__name__)
744 self.update_progressbar()
782745
783 def connection_lost(self):746 def connection_lost(self):
784 """The connection to the server was lost."""747 """The connection to the server was lost."""
@@ -826,14 +789,6 @@
826 """A file upload was unqueued."""789 """A file upload was unqueued."""
827 self.aggregator.upload_finished(command)790 self.aggregator.upload_finished(command)
828791
829 def queue_added(self, command):
830 """A command was added to the queue."""
831 self.aggregator.misc_command_queued(command)
832
833 def queue_removed(self, command):
834 """A command was removed from the queue."""
835 self.aggregator.misc_command_unqueued(command)
836
837 def queue_done(self):792 def queue_done(self):
838 """The queue is empty."""793 """The queue is empty."""
839 self.aggregator.queue_done()794 self.aggregator.queue_done()
840795
=== modified file 'ubuntuone/syncdaemon/status_listener.py'
--- ubuntuone/syncdaemon/status_listener.py 2011-02-09 08:23:04 +0000
+++ ubuntuone/syncdaemon/status_listener.py 2011-03-23 20:01:28 +0000
@@ -60,7 +60,7 @@
60 set_show_all_notifications)60 set_show_all_notifications)
6161
62 def handle_AQ_CHANGE_PUBLIC_ACCESS_OK(self, share_id, node_id, is_public,62 def handle_AQ_CHANGE_PUBLIC_ACCESS_OK(self, share_id, node_id, is_public,
63 public_url):63 public_url):
64 """The status of a published resource changed."""64 """The status of a published resource changed."""
65 if is_public:65 if is_public:
66 self.status_frontend.file_published(public_url)66 self.status_frontend.file_published(public_url)
@@ -73,8 +73,6 @@
73 self.status_frontend.download_started(command)73 self.status_frontend.download_started(command)
74 elif isinstance(command, action_queue.Upload):74 elif isinstance(command, action_queue.Upload):
75 self.status_frontend.upload_started(command)75 self.status_frontend.upload_started(command)
76 else:
77 self.status_frontend.queue_added(command)
7876
79 def handle_SYS_QUEUE_REMOVED(self, command):77 def handle_SYS_QUEUE_REMOVED(self, command):
80 """A command has been removed from the queue."""78 """A command has been removed from the queue."""
@@ -82,8 +80,6 @@
82 self.status_frontend.download_finished(command)80 self.status_frontend.download_finished(command)
83 elif isinstance(command, action_queue.Upload):81 elif isinstance(command, action_queue.Upload):
84 self.status_frontend.upload_finished(command)82 self.status_frontend.upload_finished(command)
85 else:
86 self.status_frontend.queue_removed(command)
8783
88 def handle_SYS_QUEUE_DONE(self):84 def handle_SYS_QUEUE_DONE(self):
89 """The queue has finished processing everything."""85 """The queue has finished processing everything."""

Subscribers

People subscribed via source and target branches