Merge lp:~cmiller/desktopcouch/defer-dbus-until-after-plugins into lp:desktopcouch

Proposed by Chad Miller
Status: Merged
Approved by: Chad Miller
Approved revision: 281
Merged at revision: 274
Proposed branch: lp:~cmiller/desktopcouch/defer-dbus-until-after-plugins
Merge into: lp:desktopcouch
Diff against target: 718 lines (+243/-135)
10 files modified
desktopcouch/application/local_files.py (+3/-1)
desktopcouch/application/platform/windows/tests/test_base_dirs.py (+2/-2)
desktopcouch/application/plugins/__init__.py (+13/-3)
desktopcouch/application/plugins/tests/test_plugins.py (+3/-1)
desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py (+33/-8)
desktopcouch/application/plugins/ubuntuone_pairing.py (+62/-43)
desktopcouch/application/service.py (+27/-4)
desktopcouch/application/tests/test_service.py (+88/-62)
desktopcouch/records/tests/test_mocked_server.py (+4/-3)
desktopcouch/recordtypes/contacts/tests/test_view.py (+8/-8)
To merge this branch: bzr merge lp:~cmiller/desktopcouch/defer-dbus-until-after-plugins
Reviewer Review Type Date Requested Status
dobey (community) Approve
Natalia Bidart (community) Approve
Review via email: mp+57589@code.launchpad.net

Commit message

Add ability for plugins to delay DBus service activation until they are finished processing. Make ubuntuone_pairing plugin use this. (LP: #760236)

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

Can you please make the docstring of load_plugins pep-257 compliant?

Also, I don't understand why you're passing gobject around, is that really needed?

review: Needs Fixing
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Also, a test run failed with:

===============================================================================
[FAIL]
Traceback (most recent call last):
  File "/usr/lib/python2.7/unittest/case.py", line 321, in run
    testMethod()
  File "/home/nessita/canonical/desktopcouch/review_defer-dbus-until-after-plugins/desktopcouch/recordtypes/contacts/tests/test_view.py", line 287, in test_find_contact_starting
    self.assertEqual(len(contacts), 1)
  File "/usr/lib/python2.7/unittest/case.py", line 503, in assertEqual
    assertion_func(first, second, msg=msg)
  File "/usr/lib/python2.7/unittest/case.py", line 496, in _baseAssertEqual
    raise self.failureException(msg)
exceptions.AssertionError: 2 != 1

desktopcouch.recordtypes.contacts.tests.test_view.TestLocalFiles.test_find_contact_starting

review: Needs Fixing
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

I can't reproduce the test failure in trunk, so it seems like something in this branch is generating that failure?

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Chad,

I re ran the test suite several times and the test case will not fail anymore, looks like a transient error (that should be debugged but I don't want to delay your branch anymore).

I'm approving so you can move on, but please fix all the (new) "Reimport" errors from pylint before landing.

Thanks!

review: Approve
Revision history for this message
Chad Miller (cmiller) wrote :

I've run this test in a loop more than 1200 times, and can't reproduce it. We've seen something like it on trunk before, though.

Revision history for this message
dobey (dobey) :
review: Approve
Revision history for this message
Chad Miller (cmiller) wrote :
Download full text (16.4 KiB)

The attempt to merge lp:~cmiller/desktopcouch/defer-dbus-until-after-plugins into lp:desktopcouch failed. Below is the output from the failed tests.

Apache CouchDB has started, time to relax.
Browse your desktop CouchDB at file:///tmp/tmp_DEgO4/data/couchdb.html
desktopcouch.application.migration.tests.test_migration
  TestMigration
    test_migration_deleted_flag_to_trash ... [OK]
    test_migration_in_face_of_broken_records ... [OK]
    test_migration_script_is_run ... [OK]
    test_migration_script_is_run_and_can_access_view ... [OK]
  TestRegistration
    test_register_migration_is_added_to_the_registry ... [OK]
desktopcouch.application.pair.tests.test_couchdb_io
  TestCouchdbIo
    test_get_database_names_replicatable ... [OK]
    test_get_my_host_unique_id ... [OK]
    test_mkuri ... [OK]
    test_obsfuscation ... [OK]
    test_put_dynamic_paired_host ... [OK]
    test_put_static_paired_service ... [OK]
desktopcouch.application.pair.tests.test_network_io
  TestNetworkIO
    test_successful_lifespan ... [OK]
desktopcouch.application.platform.linux.tests.test_keyring
  TestGnomeKeyring
    test_get_aouth_no_keyring ... [OK]
    test_get_oauth_canceled_store ... [OK]
    test_get_oauth_data_stored ... [OK]
    test_get_user_name_password_keyring ... [OK]
    test_get_user_name_password_no_daemon ... [OK]
    test_get_user_name_password_not_in_keyring ... [OK]
    test_get_user_name_password_user_cancel ... [OK]
desktopcouch.application.platform.windows.tests.test_base_dirs
  BaseDirsTestCase
    test_get_special_folders ... [OK]
    test_get_special_folders_cannot_get_data ... [OK]
    test_get_special_folders_cannot_open_hive ... [OK]
    test_get_special_folders_cannot_open_key ... [OK]
desktopcouch.application.platform.windows.tests.test_keyring
  TestKeyring
    test_get_oauth_data ... [OK]
    test_get_user_name_password ... [OK]
    test_get_user_name_password_no_key ... [OK]
    test_get_user_name_password_no_value ... [OK]
desktopcouch.application.plugins.tests.test_plugins
  TestLoadPlugins
    test_load_plugins ... [OK]
desktopcouch.application.plugins.tests.test_ubuntuone_pairing
  TestUbuntonePairing
    test_pair_with_ubuntuone_no_record ... [OK]
...

Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (28.6 KiB)

The attempt to merge lp:~cmiller/desktopcouch/defer-dbus-until-after-plugins into lp:desktopcouch failed. Below is the output from the failed tests.

Apache CouchDB has started, time to relax.
Browse your desktop CouchDB at file:///tmp/tmpJCnr4N/data/couchdb.html
desktopcouch.application.migration.tests.test_migration
  TestMigration
    test_migration_deleted_flag_to_trash ... [OK]
    test_migration_in_face_of_broken_records ... [OK]
    test_migration_script_is_run ... [OK]
    test_migration_script_is_run_and_can_access_view ... [OK]
  TestRegistration
    test_register_migration_is_added_to_the_registry ... [OK]
desktopcouch.application.plugins.tests.test_ubuntuone_pairing
  TestUbuntonePairing
    test_pair_with_ubuntuone_no_record ... [OK]
    test_pair_with_ubuntuone_no_view ... [OK]
    test_pair_with_ubuntuone_record_present ... [OK]
    test_pair_with_ubuntuone_user_deleted_record ... [OK]
  TestUbuntuOnePlugin
    test_got_new_credentials ... [OK]
    test_got_new_credentials_other ... [OK]
    test_listen_to_dbus ... [OK]
desktopcouch.application.plugins.tests.test_plugins
  TestLoadPlugins
    test_load_plugins ... [OK]
desktopcouch.application.pair.tests.test_network_io
  TestNetworkIO
    test_successful_lifespan ... [OK]
desktopcouch.application.pair.tests.test_couchdb_io
  TestCouchdbIo
    test_get_database_names_replicatable ... [OK]
    test_get_my_host_unique_id ... [OK]
    test_mkuri ... [OK]
    test_obsfuscation ... [OK]
    test_put_dynamic_paired_host ... [OK]
    test_put_static_paired_service ... [OK]
desktopcouch.application.tests.test_service
  TestService
    test_start_desktopcouch_replication ... [OK]
    test_start_migrate_data ... [OK]
    test_start_new_desktopcouch_with_plugins ... Traceback (most recent call last):
  File "/usr/lib/python2.7/unittest/case.py", line 321, in run
    testMethod()
  File "/usr/lib/pymodules/python2.7/mocker.py", line 146, in test_method_wrapper
    result = test_method()
  File "/home/otto/tarmac-builds/desktopcouch/trunk/desktopcouch/application/tests/test_service.py", line 135, in test_start_new_desktopcouch_with_plugins
    put_service_fn=put_service_fn)
exceptions.TypeError: fail_if_called() takes at most 1 argument (4 given)
[ERROR]
desktopcouch.application.tests.test_local_files
  TestKeyringIntegration
    test_with_auth ... [OK]
    test_with_no_...

Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (26.9 KiB)

The attempt to merge lp:~cmiller/desktopcouch/defer-dbus-until-after-plugins into lp:desktopcouch failed. Below is the output from the failed tests.

Apache CouchDB has started, time to relax.
Browse your desktop CouchDB at file:///tmp/tmpHzJDQ2/data/couchdb.html
desktopcouch.application.migration.tests.test_migration
  TestMigration
    test_migration_deleted_flag_to_trash ... [OK]
    test_migration_in_face_of_broken_records ... [OK]
    test_migration_script_is_run ... [OK]
    test_migration_script_is_run_and_can_access_view ... [OK]
  TestRegistration
    test_register_migration_is_added_to_the_registry ... [OK]
desktopcouch.application.plugins.tests.test_ubuntuone_pairing
  TestUbuntonePairing
    test_pair_with_ubuntuone_no_record ... [OK]
    test_pair_with_ubuntuone_no_view ... [OK]
    test_pair_with_ubuntuone_record_present ... [OK]
    test_pair_with_ubuntuone_user_deleted_record ... [OK]
  TestUbuntuOnePlugin
    test_got_new_credentials ... [OK]
    test_got_new_credentials_other ... [OK]
    test_listen_to_dbus ... [OK]
desktopcouch.application.plugins.tests.test_plugins
  TestLoadPlugins
    test_load_plugins ... [OK]
desktopcouch.application.pair.tests.test_network_io
  TestNetworkIO
    test_successful_lifespan ... [OK]
desktopcouch.application.pair.tests.test_couchdb_io
  TestCouchdbIo
    test_get_database_names_replicatable ... [OK]
    test_get_my_host_unique_id ... [OK]
    test_mkuri ... [OK]
    test_obsfuscation ... [OK]
    test_put_dynamic_paired_host ... [OK]
    test_put_static_paired_service ... [OK]
desktopcouch.application.tests.test_service
  TestService
    test_start_desktopcouch_replication ... [OK]
    test_start_migrate_data ... [OK]
    test_start_new_desktopcouch_with_plugins ... Traceback (most recent call last):
  File "/usr/lib/python2.7/unittest/case.py", line 321, in run
    testMethod()
  File "/usr/lib/pymodules/python2.7/mocker.py", line 146, in test_method_wrapper
    result = test_method()
  File "/home/otto/tarmac-builds/desktopcouch/trunk/desktopcouch/application/tests/test_service.py", line 135, in test_start_new_desktopcouch_with_plugins
    put_service_fn=put_service_fn)
exceptions.TypeError: fail_if_called() takes at most 1 argument (4 given)
[ERROR]
desktopcouch.application.tests.test_local_files
  TestKeyringIntegration
    test_with_auth ... [OK]
    test_with_no_...

Revision history for this message
dobey (dobey) wrote :

Something very weird is going on in the tests here. This change seems to fix it here:

=== modified file 'desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py'
--- desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py 2011-04-13 21:31:15 +0000
+++ desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py 2011-04-15 01:56:27 +0000
@@ -136,11 +136,13 @@ class TestUbuntuOnePlugin(MockerTestCase
             """Fail if we get called."""
             self.called = True

+ old_pair = uone.pair_with_ubuntuone
         uone.pair_with_ubuntuone = fail_if_called
         uone.got_new_credentials(self.couchdb_port, self.blocking_semaphores,
                                  'Unknown App', {})
         self.assertFalse(self.called, 'pair_with_ubuntuone was not expected.')
         self.mocker.replay()
+ uone.pair_with_ubuntuone = old_pair

     def test_got_new_credentials(self):
         """Check that pairing is called for Ubuntu One."""
@@ -148,11 +150,13 @@ class TestUbuntuOnePlugin(MockerTestCase
             """Check that pair_with_ubuntuone was called."""
             self.called = True

+ old_pair = uone.pair_with_ubuntuone
         uone.pair_with_ubuntuone = pass_if_called
         uone.got_new_credentials(self.couchdb_port, self.blocking_semaphores,
                                  uone.APP_NAME, {})
         self.assertTrue(self.called, 'pair_with_ubuntuone was not called.')
         self.mocker.replay()
+ uone.pair_with_ubuntuone = old_pair

     def test_listen_to_dbus(self):
         """Test that listening to credentails works."""

281. By Chad Miller

Save and restore the monkey-patched pair_with_ubuntuone function. I have no idea how this was working, but tests fail elsewhere.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'desktopcouch/application/local_files.py'
--- desktopcouch/application/local_files.py 2011-04-08 20:31:22 +0000
+++ desktopcouch/application/local_files.py 2011-04-15 21:47:33 +0000
@@ -83,9 +83,11 @@
83 if "-hashed-" in bookmark_file_contents:83 if "-hashed-" in bookmark_file_contents:
84 raise ValueError("Basic-auth cred lost.")84 raise ValueError("Basic-auth cred lost.")
85 # trial run, check sanity.85 # trial run, check sanity.
86 # pylint: disable=W0106
86 re.findall(87 re.findall(
87 "<!-- !!([^!]+)!!([^!]+)!! -->",88 "<!-- !!([^!]+)!!([^!]+)!! -->",
88 bookmark_file_contents)[-1]89 bookmark_file_contents)[-1]
90 # pylint: enable=W0106
89 self._fill_from_file(self.file_name_used)91 self._fill_from_file(self.file_name_used)
90 return92 return
91 except (IOError, ValueError, IndexError):93 except (IOError, ValueError, IndexError):
@@ -196,7 +198,7 @@
196 for d in (run_dir, db_dir, config_dir):198 for d in (run_dir, db_dir, config_dir):
197 try:199 try:
198 os.makedirs(d, 0700)200 os.makedirs(d, 0700)
199 except OSError, ex:201 except OSError:
200 pass # Probably that it already exists.202 pass # Probably that it already exists.
201 try:203 try:
202 os.chmod(d, 0700)204 os.chmod(d, 0700)
203205
=== modified file 'desktopcouch/application/platform/windows/tests/test_base_dirs.py'
--- desktopcouch/application/platform/windows/tests/test_base_dirs.py 2011-01-25 17:58:49 +0000
+++ desktopcouch/application/platform/windows/tests/test_base_dirs.py 2011-04-15 21:47:33 +0000
@@ -63,7 +63,7 @@
63 self.mocker.result('hive')63 self.mocker.result('hive')
64 self._winreg.OpenKey('hive', SHELL_FOLDERS_KEY)64 self._winreg.OpenKey('hive', SHELL_FOLDERS_KEY)
65 self.mocker.result('key')65 self.mocker.result('key')
66 self._winreg.QueryInfoKey('key')[1]66 self._winreg.QueryInfoKey('key')[1] # pylint: disable=W0106
67 self.mocker.throw(Exception('Cannot get info.'))67 self.mocker.throw(Exception('Cannot get info.'))
68 self._winreg.CloseKey('hive')68 self._winreg.CloseKey('hive')
69 self._winreg.CloseKey('key')69 self._winreg.CloseKey('key')
@@ -78,7 +78,7 @@
78 self.mocker.result('hive')78 self.mocker.result('hive')
79 self._winreg.OpenKey('hive', SHELL_FOLDERS_KEY)79 self._winreg.OpenKey('hive', SHELL_FOLDERS_KEY)
80 self.mocker.result('key')80 self.mocker.result('key')
81 self._winreg.QueryInfoKey('key')[1]81 self._winreg.QueryInfoKey('key')[1] # pylint: disable=W0106
82 self.mocker.result(1)82 self.mocker.result(1)
83 self._winreg.EnumValue('key', 0)83 self._winreg.EnumValue('key', 0)
84 self.mocker.result(('AppData', 'path', 1))84 self.mocker.result(('AppData', 'path', 1))
8585
=== modified file 'desktopcouch/application/plugins/__init__.py'
--- desktopcouch/application/plugins/__init__.py 2011-01-24 14:30:34 +0000
+++ desktopcouch/application/plugins/__init__.py 2011-04-15 21:47:33 +0000
@@ -19,8 +19,18 @@
19DESKTOPCOUCH_PLUGIN_PATHS = [os.path.join(os.path.dirname(__file__))]19DESKTOPCOUCH_PLUGIN_PATHS = [os.path.join(os.path.dirname(__file__))]
2020
2121
22def load_plugins(couchdb_port):22def load_plugins(couchdb_port, blocking_semaphores, gobject):
23 """Load the desktopcouch application plug-ins."""23 """Load the desktopcouch application plug-ins.
24
25 The blocking_semaphores set is OPTIONALLY mutated by any plugin to signal
26 that the service is not ready until a plugin has finished its asynchronous
27 operations. Plugins may add a distinguishing object to the set, and it
28 must remove what it adds when it is finished.
29
30 couchdb -- the integer of the port number of the running couchdb
31 blocking_semaphores -- the set() of semaphores, which we will mutate
32 gobject -- the mainloop module. always 'gobject' except when testing.
33 """
24 plugin_names = set()34 plugin_names = set()
25 for path in DESKTOPCOUCH_PLUGIN_PATHS:35 for path in DESKTOPCOUCH_PLUGIN_PATHS:
26 try:36 try:
@@ -37,6 +47,6 @@
37 modpath = name.replace(os.path.sep, '.')[:-3]47 modpath = name.replace(os.path.sep, '.')[:-3]
38 try:48 try:
39 plugin = __import__(modpath, None, None, [''])49 plugin = __import__(modpath, None, None, [''])
40 plugin.plugin_init(couchdb_port)50 plugin.plugin_init(couchdb_port, blocking_semaphores, gobject)
41 except (ImportError, AttributeError):51 except (ImportError, AttributeError):
42 logging.warning('Failed to load plug-in: %s', modpath)52 logging.warning('Failed to load plug-in: %s', modpath)
4353
=== modified file 'desktopcouch/application/plugins/tests/test_plugins.py'
--- desktopcouch/application/plugins/tests/test_plugins.py 2011-01-26 22:32:59 +0000
+++ desktopcouch/application/plugins/tests/test_plugins.py 2011-04-15 21:47:33 +0000
@@ -28,6 +28,8 @@
2828
29 def setUp(self):29 def setUp(self):
30 self.couchdb_port = platform.find_port(ctx=test_context)30 self.couchdb_port = platform.find_port(ctx=test_context)
31 self.blockers = set()
32 self.gobject = None
3133
32 def test_load_plugins(self):34 def test_load_plugins(self):
33 """Test that plug-ins are loaded correctly."""35 """Test that plug-ins are loaded correctly."""
@@ -44,7 +46,7 @@
44 self._imported = modname46 self._imported = modname
45 old_import = __import__47 old_import = __import__
46 __builtins__['__import__'] = _fake_import48 __builtins__['__import__'] = _fake_import
47 plugins.load_plugins(self.couchdb_port)49 plugins.load_plugins(self.couchdb_port, self.blockers, self.gobject)
48 __builtins__['__import__'] = old_import50 __builtins__['__import__'] = old_import
49 plugins.DESKTOPCOUCH_PLUGIN_PATHS = old_paths51 plugins.DESKTOPCOUCH_PLUGIN_PATHS = old_paths
50 self.assertEqual(self._imported, __name__)52 self.assertEqual(self._imported, __name__)
5153
=== modified file 'desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py'
--- desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py 2011-01-26 22:32:59 +0000
+++ desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py 2011-04-15 21:47:33 +0000
@@ -38,9 +38,11 @@
38 self.couchdb_port = self.mocker.mock()38 self.couchdb_port = self.mocker.mock()
39 self.put_static_paired_service = self.mocker.mock()39 self.put_static_paired_service = self.mocker.mock()
40 self.database_class = self.mocker.mock()40 self.database_class = self.mocker.mock()
41 self.blocking_semaphores = self.mocker.mock()
4142
42 def test_pair_with_ubuntuone_no_view(self):43 def test_pair_with_ubuntuone_no_view(self):
43 """Test that when the view is not present it is indeed created."""44 """Test that when the view is not present it is indeed created."""
45 # plugin_init adds name to blocking semaphores, but we remove it.
44 self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD)46 self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD)
45 self.mocker.result(False)47 self.mocker.result(False)
46 # we are interested in the fact that the view is created48 # we are interested in the fact that the view is created
@@ -50,8 +52,11 @@
50 self.couchdb.execute_view(U1_PAIR_RECORD, U1_PAIR_RECORD)52 self.couchdb.execute_view(U1_PAIR_RECORD, U1_PAIR_RECORD)
51 self.mocker.result([])53 self.mocker.result([])
52 self.put_static_paired_service(None, 'ubuntuone', ctx=None, uri=ANY)54 self.put_static_paired_service(None, 'ubuntuone', ctx=None, uri=ANY)
55 self.blocking_semaphores.discard(ANY)
56
53 self.mocker.replay()57 self.mocker.replay()
54 pair_with_ubuntuone(self.couchdb_port, self.couchdb,58 pair_with_ubuntuone(self.couchdb_port, self.blocking_semaphores,
59 management_db=self.couchdb,
55 db_class=self.database_class,60 db_class=self.database_class,
56 put_service_fn=self.put_static_paired_service)61 put_service_fn=self.put_static_paired_service)
57 self.mocker.verify()62 self.mocker.verify()
@@ -59,21 +64,27 @@
59 def test_pair_with_ubuntuone_no_record(self):64 def test_pair_with_ubuntuone_no_record(self):
60 """Ensure pairing is not done when there are no records ."""65 """Ensure pairing is not done when there are no records ."""
61 # execute the steps when no records are returned by the view66 # execute the steps when no records are returned by the view
67 # plugin_init adds name to blocking semaphores, but we remove it.
62 self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD)68 self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD)
63 self.mocker.result(True)69 self.mocker.result(True)
64 self.couchdb.execute_view(U1_PAIR_RECORD, U1_PAIR_RECORD)70 self.couchdb.execute_view(U1_PAIR_RECORD, U1_PAIR_RECORD)
65 self.mocker.result([])71 self.mocker.result([])
66 self.put_static_paired_service(None, 'ubuntuone', ctx=None, uri=ANY)72 self.put_static_paired_service(None, 'ubuntuone', ctx=None, uri=ANY)
73 self.blocking_semaphores.discard(ANY)
74
67 self.mocker.replay()75 self.mocker.replay()
68 pair_with_ubuntuone(self.couchdb_port, self.couchdb,76 pair_with_ubuntuone(self.couchdb_port, self.blocking_semaphores,
77 management_db=self.couchdb,
69 db_class=self.database_class,78 db_class=self.database_class,
70 put_service_fn=self.put_static_paired_service)79 put_service_fn=self.put_static_paired_service)
80
71 self.mocker.verify()81 self.mocker.verify()
7282
73 def test_pair_with_ubuntuone_user_deleted_record(self):83 def test_pair_with_ubuntuone_user_deleted_record(self):
74 """Ensure pairing is not done when the user explicitly removed it."""84 """Ensure pairing is not done when the user explicitly removed it."""
75 # create a mock object that will be the result from the view85 # create a mock object that will be the result from the view
76 row = self.mocker.mock()86 row = self.mocker.mock()
87 # plugin_init adds name to blocking semaphores, but we remove it.
77 # execute the steps to show that the user deleted the record88 # execute the steps to show that the user deleted the record
78 self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD)89 self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD)
79 self.mocker.result(True)90 self.mocker.result(True)
@@ -82,14 +93,18 @@
82 # FIXME does this do anything?93 # FIXME does this do anything?
83 _ = row.value94 _ = row.value
84 self.mocker.result(1)95 self.mocker.result(1)
96 self.blocking_semaphores.discard(ANY)
97
85 self.mocker.replay()98 self.mocker.replay()
86 pair_with_ubuntuone(self.couchdb_port, self.couchdb)99 pair_with_ubuntuone(self.couchdb_port, self.blocking_semaphores,
100 management_db=self.couchdb)
87 self.mocker.verify()101 self.mocker.verify()
88102
89 def test_pair_with_ubuntuone_record_present(self):103 def test_pair_with_ubuntuone_record_present(self):
90 """Ensure pairing is not done when the record is already present."""104 """Ensure pairing is not done when the record is already present."""
91 # create a mock object that will be the result from the view105 # create a mock object that will be the result from the view
92 row = self.mocker.mock()106 row = self.mocker.mock()
107 # plugin_init adds name to blocking semaphores, but we remove it.
93 # execute the steps to show that the user deleted the record108 # execute the steps to show that the user deleted the record
94 self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD)109 self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD)
95 self.mocker.result(True)110 self.mocker.result(True)
@@ -98,8 +113,11 @@
98 # FIXME does this do anything?113 # FIXME does this do anything?
99 _ = row.value114 _ = row.value
100 self.mocker.result(0)115 self.mocker.result(0)
116 self.blocking_semaphores.discard(ANY)
117
101 self.mocker.replay()118 self.mocker.replay()
102 pair_with_ubuntuone(self.couchdb_port, self.couchdb)119 pair_with_ubuntuone(self.couchdb_port, self.blocking_semaphores,
120 management_db=self.couchdb)
103 self.mocker.verify()121 self.mocker.verify()
104122
105123
@@ -109,6 +127,7 @@
109 def setUp(self):127 def setUp(self):
110 super(TestUbuntuOnePlugin, self).setUp()128 super(TestUbuntuOnePlugin, self).setUp()
111 self.couchdb_port = self.mocker.mock()129 self.couchdb_port = self.mocker.mock()
130 self.blocking_semaphores = self.mocker.mock()
112 self.called = False131 self.called = False
113132
114 def test_got_new_credentials_other(self):133 def test_got_new_credentials_other(self):
@@ -117,21 +136,27 @@
117 """Fail if we get called."""136 """Fail if we get called."""
118 self.called = True137 self.called = True
119138
139 saved_pair = uone.pair_with_ubuntuone
120 uone.pair_with_ubuntuone = fail_if_called140 uone.pair_with_ubuntuone = fail_if_called
121 uone.got_new_credentials(self.couchdb_port, 'Unknown App', {})141 uone.got_new_credentials(self.couchdb_port, self.blocking_semaphores,
142 'Unknown App', {})
122 self.assertFalse(self.called, 'pair_with_ubuntuone was not expected.')143 self.assertFalse(self.called, 'pair_with_ubuntuone was not expected.')
123 self.mocker.replay()144 self.mocker.replay()
145 uone.pair_with_ubuntuone = saved_pair
124146
125 def test_got_new_credentials(self):147 def test_got_new_credentials(self):
126 """Check that pairing is called for Ubuntu One."""148 """Check that pairing is called for Ubuntu One."""
127 def pass_if_called(db=None):149 def pass_if_called(db=None, semaphores=None):
128 """Check that pair_with_ubuntuone was called."""150 """Check that pair_with_ubuntuone was called."""
129 self.called = True151 self.called = True
130152
153 saved_pair = uone.pair_with_ubuntuone
131 uone.pair_with_ubuntuone = pass_if_called154 uone.pair_with_ubuntuone = pass_if_called
132 uone.got_new_credentials(self.couchdb_port, uone.APP_NAME, {})155 uone.got_new_credentials(self.couchdb_port, self.blocking_semaphores,
156 uone.APP_NAME, {})
133 self.assertTrue(self.called, 'pair_with_ubuntuone was not called.')157 self.assertTrue(self.called, 'pair_with_ubuntuone was not called.')
134 self.mocker.replay()158 self.mocker.replay()
159 uone.pair_with_ubuntuone = saved_pair
135160
136 def test_listen_to_dbus(self):161 def test_listen_to_dbus(self):
137 """Test that listening to credentails works."""162 """Test that listening to credentails works."""
@@ -161,4 +186,4 @@
161186
162 self.mocker.replay()187 self.mocker.replay()
163188
164 uone.listen_to_dbus(self.couchdb_port)189 uone.listen_to_dbus(self.couchdb_port, self.blocking_semaphores)
165190
=== modified file 'desktopcouch/application/plugins/ubuntuone_pairing.py'
--- desktopcouch/application/plugins/ubuntuone_pairing.py 2011-01-27 19:25:23 +0000
+++ desktopcouch/application/plugins/ubuntuone_pairing.py 2011-04-15 21:47:33 +0000
@@ -24,6 +24,7 @@
24from desktopcouch.application.server import DesktopDatabase24from desktopcouch.application.server import DesktopDatabase
25from ubuntuone.clientdefs import APP_NAME25from ubuntuone.clientdefs import APP_NAME
2626
27PLUGIN_NAME = __name__
27U1_PAIR_RECORD = "ubuntu_one_pair_record"28U1_PAIR_RECORD = "ubuntu_one_pair_record"
28MAP_JS = """function(doc) {29MAP_JS = """function(doc) {
29 if (doc.service_name == "ubuntuone") {30 if (doc.service_name == "ubuntuone") {
@@ -33,48 +34,57 @@
33"""34"""
3435
3536
36def pair_with_ubuntuone(couchdb_port, management_db=None,37def pair_with_ubuntuone(couchdb_port, blocking_semaphores,
38 management_db=None,
37 db_class=DesktopDatabase,39 db_class=DesktopDatabase,
38 put_service_fn=put_static_paired_service):40 put_service_fn=put_static_paired_service):
39 """Adds a pairing record with ubuntu one when needed."""41 """Adds a pairing record with ubuntu one when needed."""
40 # Use explicit uri so that we do not access dbus service.42 try:
41 uri = "http://localhost:%s" % (couchdb_port,)43 # Use explicit uri so that we do not access dbus service.
42 if not management_db:44 uri = "http://localhost:%s" % (couchdb_port,)
43 management_db = db_class("management", uri=uri, create=True, ctx=None)45 if not management_db:
44 # we indeed have credentials to add to the pairing records46 management_db = db_class("management", uri=uri, create=True,
45 # but first we ensure that the required view is present47 ctx=None)
46 if not management_db.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD):48 # we indeed have credentials to add to the pairing records
47 management_db.add_view(49 # but first we ensure that the required view is present
48 U1_PAIR_RECORD, MAP_JS, design_doc=U1_PAIR_RECORD)50 if not management_db.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD):
49 view_results = management_db.execute_view(U1_PAIR_RECORD, U1_PAIR_RECORD)51 management_db.add_view(
50 pairing_found = False52 U1_PAIR_RECORD, MAP_JS, design_doc=U1_PAIR_RECORD)
51 # Results should contain either one row or no rows53 view_results = management_db.execute_view(U1_PAIR_RECORD,
52 # If there is one row, its value will be 0, meaning that there is54 U1_PAIR_RECORD)
53 # already an Ubuntu One pairing record, or 1, meaning that there55 pairing_found = False
54 # was an Ubuntu One pairing record but it has since been unpaired56 # Results should contain either one row or no rows
55 # Only create a new record if there is not one already. Specifically,57 # If there is one row, its value will be 0, meaning that there is
56 # do not add the record if there is a deleted one, as this means58 # already an Ubuntu One pairing record, or 1, meaning that there
57 # that the user explicitly unpaired it!59 # was an Ubuntu One pairing record but it has since been unpaired
58 for row in view_results:60 # Only create a new record if there is not one already. Specifically,
59 pairing_found = True61 # do not add the record if there is a deleted one, as this means
60 if row.value == 1:62 # that the user explicitly unpaired it!
61 logging.debug("Not adding desktopcouch pairing since the user "63 for row in view_results:
62 "has explicitly unpaired with Ubuntu One")64 pairing_found = True
63 else:65 if row.value == 1:
64 logging.debug("Not adding desktopcouch pairing since we are "66 logging.debug("Not adding desktopcouch pairing since the user "
65 "already paired")67 "has explicitly unpaired with Ubuntu One")
66 if not pairing_found:68 else:
67 put_service_fn(None, "ubuntuone", uri=uri, ctx=None)69 logging.debug("Not adding desktopcouch pairing since we are "
68 logging.debug("Pairing desktopcouch with Ubuntu One")70 "already paired")
6971 if not pairing_found:
7072 put_service_fn(None, "ubuntuone", uri=uri, ctx=None)
71def got_new_credentials(couchdb_port, app_name, credentials):73 logging.debug("Pairing desktopcouch with Ubuntu One")
74
75 finally:
76 logging.info("removing semaphore for %s", PLUGIN_NAME)
77 blocking_semaphores.discard(PLUGIN_NAME)
78
79
80def got_new_credentials(couchdb_port, blocking_semaphores,
81 app_name, credentials):
72 """Pair with Ubuntu One when we get the new credentials."""82 """Pair with Ubuntu One when we get the new credentials."""
73 if app_name == APP_NAME:83 if app_name == APP_NAME:
74 pair_with_ubuntuone(couchdb_port)84 pair_with_ubuntuone(couchdb_port, blocking_semaphores)
7585
7686
77def listen_to_dbus(couchdb_port):87def listen_to_dbus(couchdb_port, blocking_semaphores):
78 """Set up the signal handler on D-Bus for Ubuntu One pairing."""88 """Set up the signal handler on D-Bus for Ubuntu One pairing."""
79 import dbus89 import dbus
80 bus = dbus.SessionBus()90 bus = dbus.SessionBus()
@@ -82,7 +92,9 @@
82 try:92 try:
83 import ubuntu_sso93 import ubuntu_sso
8494
85 receiver = lambda *args: got_new_credentials(couchdb_port, *args)95 receiver = lambda *args: \
96 got_new_credentials(couchdb_port, blocking_semaphores,
97 *args)
8698
87 iface = ubuntu_sso.DBUS_CREDENTIALS_IFACE99 iface = ubuntu_sso.DBUS_CREDENTIALS_IFACE
88 bus.add_signal_receiver(handler_function=receiver,100 bus.add_signal_receiver(handler_function=receiver,
@@ -96,13 +108,20 @@
96 sso_backend.find_credentials(APP_NAME, {})108 sso_backend.find_credentials(APP_NAME, {})
97 except ImportError:109 except ImportError:
98 logging.info('Ubuntu SSO is not available.')110 logging.info('Ubuntu SSO is not available.')
99111 blocking_semaphores.discard(PLUGIN_NAME)
100112
101def plugin_init(couchdb_port):113
114def plugin_init(couchdb_port, blocking_semaphores, gobject):
102 """Set up the signal handler for pairing with Ubuntu One."""115 """Set up the signal handler for pairing with Ubuntu One."""
103 logging.info('Loaded Ubuntu One extension for desktopcouch.')116 logging.info('Loaded Ubuntu One extension for desktopcouch.')
104 if sys.platform == 'win32':117 if sys.platform == 'win32':
105 logging.warning('Windows support for Ubuntu One is not yet ready.')118 logging.warning('Windows support for Ubuntu One is not yet ready.')
106 else:119 else:
107 import gobject120
108 gobject.idle_add(listen_to_dbus, couchdb_port)121 # Signal that we are critical for desktopcouch usage, and the server
122 # must not begin until we are finished. We are responsible for
123 # removing this item from the list.
124 logging.info("adding %s to to blocking semaphore list", PLUGIN_NAME)
125 blocking_semaphores.add(PLUGIN_NAME)
126
127 gobject.idle_add(listen_to_dbus, couchdb_port, blocking_semaphores)
109128
=== modified file 'desktopcouch/application/service.py'
--- desktopcouch/application/service.py 2011-01-31 21:49:22 +0000
+++ desktopcouch/application/service.py 2011-04-15 21:47:33 +0000
@@ -39,6 +39,7 @@
39import logging39import logging
40import logging.handlers40import logging.handlers
41import signal41import signal
42import gobject
4243
43from desktopcouch.application import local_files44from desktopcouch.application import local_files
44from desktopcouch.application import replication45from desktopcouch.application import replication
@@ -84,7 +85,8 @@
84 replication_actions=replication,85 replication_actions=replication,
85 advertiser_factory=PortAdvertiser, set_logging=set_up_logging,86 advertiser_factory=PortAdvertiser, set_logging=set_up_logging,
86 fork=os.fork, nice=os.nice,87 fork=os.fork, nice=os.nice,
87 kill=os.kill, sleep=time.sleep):88 kill=os.kill, sleep=time.sleep, set_type=set,
89 gobject_module=gobject):
88 self._mainloop = main_loop90 self._mainloop = main_loop
89 self._pid_finder = pid_finder91 self._pid_finder = pid_finder
90 self._port_finder = port_finder92 self._port_finder = port_finder
@@ -97,6 +99,8 @@
97 self._nice = nice99 self._nice = nice
98 self._kill = kill100 self._kill = kill
99 self._sleep = sleep101 self._sleep = sleep
102 self._set = set_type
103 self._gobject = gobject_module
100 # pylint: enable=C0301104 # pylint: enable=C0301
101105
102 def _start_replicator_main(self, couchdb_port):106 def _start_replicator_main(self, couchdb_port):
@@ -112,11 +116,30 @@
112 replication.tear_down(*replication_runtime)116 replication.tear_down(*replication_runtime)
113117
114 def _start_server_main(self, couchdb_port):118 def _start_server_main(self, couchdb_port):
115 """Start server."""119 """Start server answering DBus calls, and run plugins first."""
116 self._advertiser_factory(self._mainloop.stop, self._ctx)120
121 def if_all_semaphores_cleared(blocking_semaphores,
122 func, *args, **kwargs):
123 """Run a function if no semaphores exist, else try later."""
124 if blocking_semaphores:
125 return True # Make idle call try us again.
126 else:
127 func(*args, **kwargs)
128 return False # Handled!
129
130 blocking_semaphores = self._set()
131 load_plugins(couchdb_port, blocking_semaphores, self._gobject)
132
133 # Answering queries on DBus signals that we are ready for users
134 # to connect. We mustn't begin that until every plugin has a chance
135 # to run to completion if it needs it.
136 self._gobject.idle_add(if_all_semaphores_cleared, blocking_semaphores,
137 self._advertiser_factory,
138 self._mainloop.stop,
139 self._ctx)
140
117 logging.debug("starting dbus main loop")141 logging.debug("starting dbus main loop")
118 try:142 try:
119 load_plugins(couchdb_port)
120 self._mainloop.run()143 self._mainloop.run()
121 finally:144 finally:
122 logging.debug("ending dbus main loop")145 logging.debug("ending dbus main loop")
123146
=== modified file 'desktopcouch/application/tests/test_service.py'
--- desktopcouch/application/tests/test_service.py 2011-01-27 19:25:23 +0000
+++ desktopcouch/application/tests/test_service.py 2011-04-15 21:47:33 +0000
@@ -37,6 +37,8 @@
37 self._replication = self.mocker.mock()37 self._replication = self.mocker.mock()
38 self._advertiser = self.mocker.mock()38 self._advertiser = self.mocker.mock()
39 self._resources = self.mocker.mock()39 self._resources = self.mocker.mock()
40 self._set = self.mocker.mock()
41 self._gobject = self.mocker.mock()
40 self._service = DesktopcouchService(self._mainloop,42 self._service = DesktopcouchService(self._mainloop,
41 pid_finder=self._pid_finder,43 pid_finder=self._pid_finder,
42 port_finder=self._port_finder,44 port_finder=self._port_finder,
@@ -48,65 +50,89 @@
48 fork=self._fork,50 fork=self._fork,
49 nice=self._nice,51 nice=self._nice,
50 kill=self._kill,52 kill=self._kill,
51 sleep=self._sleep)53 sleep=self._sleep,
5254 set_type=self._set,
53 def test_start_new_desktopcouch_no_extensions(self):55 gobject_module=self._gobject)
54 """Test that desktopcouch is started.56
5557 self.gobject_idle_task_list = list()
56 We test that when the pid cannot be found we ensure58
57 that the desktopcouch instance is started and that the59 def test_start_new_desktopcouch_with_plugins(self):
58 start as the dbus service,60 """Test that desktopcouch is started.
59 """61
60 self._pid_finder(start_if_not_running=False, ctx=self._ctx)62 We test that when the pid cannot be found we ensure
61 self.mocker.result(None)63 that the desktopcouch instance is started and that the
62 self._pid_finder(start_if_not_running=True, ctx=self._ctx)64 start as the dbus service,
63 self.mocker.result(self._pid_result)65 """
64 self._port_finder(pid=self._pid_result, ctx=self._ctx)66 self._pid_finder(start_if_not_running=False, ctx=self._ctx)
65 self.mocker.result(self._port_result)67 self.mocker.result(None)
66 self._fork()68 self._pid_finder(start_if_not_running=True, ctx=self._ctx)
67 self.mocker.result(234)69 self.mocker.result(self._pid_result)
68 self._fork()70 self._port_finder(pid=self._pid_result, ctx=self._ctx)
69 self.mocker.result(234)71 self.mocker.result(self._port_result)
70 # XXX: call this?72 self._fork()
71 self._mainloop.stop # pylint: disable=W010473 self.mocker.result(234) # We are parent
72 self.mocker.result(ANY)74 self._fork()
73 self._advertiser(ANY, self._ctx)75 self.mocker.result(234) # We are parent
74 self._mainloop.run()76
75 self._stop_couchdb(ctx=self._ctx)77 # plugins load
76 self._kill(234, signal.SIGTERM)78 semaphores = self.mocker.mock()
77 self._sleep(1)79 self._set()
78 self._kill(234, signal.SIGKILL)80 self.mocker.result(semaphores)
79 self.mocker.replay()81
80 self._service.start()82 self._mainloop.stop # pylint: disable=W0104
8183 self.mocker.result(ANY)
82 def test_start_new_desktopcouch_extensions(self):84
83 """Test that desktopcouch is started.85 self._gobject.idle_add(ANY, self._port_result, semaphores)
8486 self._gobject.idle_add(ANY, semaphores, self._advertiser, ANY,
85 We test that when the pid cannot be found we ensure87 self._ctx)
86 that the desktopcouch instance is started and that the88
87 start as the dbus service,89 self._mainloop.run()
88 """90
89 self._pid_finder(start_if_not_running=False, ctx=self._ctx)91 # Tasks are added to the mainloop's idle queue. With that^
90 self.mocker.result(None)92 # mainloop.run, they'd be called. Simulate their call.
91 self._pid_finder(start_if_not_running=True, ctx=self._ctx)93
92 self.mocker.result(self._pid_result)94 # Idle loop to add plugins calls a plugin. ubuntuone_pairing
93 self._port_finder(pid=self._pid_result, ctx=self._ctx)95 semaphores.add(ANY) # A plugin asserts it must be completed.
94 self.mocker.result(self._port_result)96
95 self._fork()97 # Idle loop calls plugin for ubuntuone_pairing, which fires up DBus
96 self.mocker.result(234)98 # client to get credentials from ubuntu-login app. When that returns,
97 self._fork()99 # it calls got_new_credentials, which calls pair_with_ubuntuone.
98 self.mocker.result(234)100
99 # XXX: call this?101 # Mock call to pair_with_ubuntuone
100 self._mainloop.stop # pylint: disable=W0104102 management_db = self.mocker.mock()
101 self.mocker.result(ANY)103 put_service_fn = self.mocker.mock()
102 self._advertiser(ANY, self._ctx)104
103 self._mainloop.run()105 bool(management_db)
104 self._stop_couchdb(ctx=self._ctx)106 self.mocker.result(True)
105 self._kill(234, signal.SIGTERM)107
106 self._sleep(1)108 management_db.view_exists(ANY, ANY)
107 self._kill(234, signal.SIGKILL)109 self.mocker.result(False)
108 self.mocker.replay()110 management_db.add_view(ANY, ANY, design_doc=ANY)
109 self._service.start()111
112 row = self.mocker.mock()
113 management_db.execute_view(ANY, ANY)
114 self.mocker.result([row])
115
116 row.value # pylint: disable=W0104
117 self.mocker.result(1)
118
119 semaphores.discard(ANY)
120
121 # and then dbus service is ready to answer queries.
122
123 self._stop_couchdb(ctx=self._ctx)
124 self._kill(234, signal.SIGTERM)
125 self._sleep(1)
126 self._kill(234, signal.SIGKILL)
127
128 self.mocker.replay()
129
130 self._service.start()
131 # Manually do what dbus idle-loop would do.
132 import desktopcouch.application.plugins.ubuntuone_pairing as u_p
133 u_p.pair_with_ubuntuone(self._port_result, semaphores,
134 management_db=management_db,
135 put_service_fn=put_service_fn)
110136
111 def test_start_desktopcouch_replication(self):137 def test_start_desktopcouch_replication(self):
112 """ Test that the repliciation works.138 """ Test that the repliciation works.
@@ -119,7 +145,7 @@
119 self._port_finder(pid=self._pid_result, ctx=self._ctx)145 self._port_finder(pid=self._pid_result, ctx=self._ctx)
120 self.mocker.result(self._port_result)146 self.mocker.result(self._port_result)
121 self._fork()147 self._fork()
122 self.mocker.result(0)148 self.mocker.result(0) # We are child process
123 self._nice(10)149 self._nice(10)
124 self._replication.set_up(ANY)150 self._replication.set_up(ANY)
125 self._mainloop.run()151 self._mainloop.run()
@@ -146,9 +172,9 @@
146 self._port_finder(pid=self._pid_result, ctx=self._ctx)172 self._port_finder(pid=self._pid_result, ctx=self._ctx)
147 self.mocker.result(self._port_result)173 self.mocker.result(self._port_result)
148 self._fork()174 self._fork()
149 self.mocker.result(567)175 self.mocker.result(567) # We are parent process
150 self._fork()176 self._fork()
151 self.mocker.result(0)177 self.mocker.result(0) # We are child process
152 self._sleep(ANY)178 self._sleep(ANY)
153 self._ctx.db_dir # searching for files # pylint: disable=W0104179 self._ctx.db_dir # searching for files # pylint: disable=W0104
154 self.mocker.result("/tmp/migration-data/does/not/exist")180 self.mocker.result("/tmp/migration-data/does/not/exist")
155181
=== modified file 'desktopcouch/records/tests/test_mocked_server.py'
--- desktopcouch/records/tests/test_mocked_server.py 2011-04-04 18:54:26 +0000
+++ desktopcouch/records/tests/test_mocked_server.py 2011-04-15 21:47:33 +0000
@@ -61,6 +61,7 @@
6161
6262
63class TestMockedCouchDatabaseCreateStates(MockerTestCase):63class TestMockedCouchDatabaseCreateStates(MockerTestCase):
64 """Mocked Couch Database tests for create= flag states."""
64 def setUp(self):65 def setUp(self):
65 """Set up tests."""66 """Set up tests."""
66 super(TestMockedCouchDatabaseCreateStates, self).setUp()67 super(TestMockedCouchDatabaseCreateStates, self).setUp()
@@ -85,7 +86,7 @@
85 self.mocker.result({'update_seq': []})86 self.mocker.result({'update_seq': []})
8687
87 self.mocker.replay()88 self.mocker.replay()
88 database = DesktopDatabase(self.dbname, uri=self.uri,89 DesktopDatabase(self.dbname, uri=self.uri,
89 record_factory=self.record_factory, create=True,90 record_factory=self.record_factory, create=True,
90 server_class=self.server_class,91 server_class=self.server_class,
91 oauth_tokens=self.oauth_tokens, ctx=self.ctx)92 oauth_tokens=self.oauth_tokens, ctx=self.ctx)
@@ -105,7 +106,7 @@
105 info["update_seq"]106 info["update_seq"]
106 self.mocker.result({})107 self.mocker.result({})
107 self.mocker.replay()108 self.mocker.replay()
108 database = DesktopDatabase(self.dbname, uri=self.uri,109 DesktopDatabase(self.dbname, uri=self.uri,
109 record_factory=self.record_factory, create=True,110 record_factory=self.record_factory, create=True,
110 server_class=self.server_class,111 server_class=self.server_class,
111 oauth_tokens=self.oauth_tokens, ctx=self.ctx)112 oauth_tokens=self.oauth_tokens, ctx=self.ctx)
@@ -140,7 +141,7 @@
140 self.mocker.result({})141 self.mocker.result({})
141142
142 self.mocker.replay()143 self.mocker.replay()
143 database = DesktopDatabase(self.dbname, uri=self.uri,144 DesktopDatabase(self.dbname, uri=self.uri,
144 record_factory=self.record_factory, create=False,145 record_factory=self.record_factory, create=False,
145 server_class=self.server_class,146 server_class=self.server_class,
146 oauth_tokens=self.oauth_tokens, ctx=self.ctx)147 oauth_tokens=self.oauth_tokens, ctx=self.ctx)
147148
=== modified file 'desktopcouch/recordtypes/contacts/tests/test_view.py'
--- desktopcouch/recordtypes/contacts/tests/test_view.py 2011-01-05 22:21:04 +0000
+++ desktopcouch/recordtypes/contacts/tests/test_view.py 2011-04-15 21:47:33 +0000
@@ -280,29 +280,29 @@
280280
281 contacts = list(281 contacts = list(
282 view.find_contacts_starting(self.db, first_name="Frances"))282 view.find_contacts_starting(self.db, first_name="Frances"))
283 self.assertEqual(len(contacts), 1)283 self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,))
284284
285 contacts = list(285 contacts = list(
286 view.find_contacts_starting(self.db, birth_date="1918"))286 view.find_contacts_starting(self.db, birth_date="1918"))
287 self.assertEqual(len(contacts), 1)287 self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,))
288288
289 contacts = list(289 contacts = list(
290 view.find_contacts_starting(self.db, birth_date="1918-08"))290 view.find_contacts_starting(self.db, birth_date="1918-08"))
291 self.assertEqual(len(contacts), 1)291 self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,))
292292
293 contacts = list(293 contacts = list(
294 view.find_contacts_starting(self.db, wedding_date="1970"))294 view.find_contacts_starting(self.db, wedding_date="1970"))
295 self.assertEqual(len(contacts), 1)295 self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,))
296296
297 contacts = list(297 contacts = list(
298 view.find_contacts_starting(298 view.find_contacts_starting(
299 self.db, email_addressesaddress="blah.example.com"))299 self.db, email_addressesaddress="blah.example.com"))
300 self.assertEqual(len(contacts), 1)300 self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,))
301301
302 contacts = list(302 contacts = list(
303 view.find_contacts_starting(303 view.find_contacts_starting(
304 self.db, email_addressesaddress="berkeley"))304 self.db, email_addressesaddress="berkeley"))
305 self.assertEqual(len(contacts), 1)305 self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,))
306306
307 contacts = list(307 contacts = list(
308 view.find_contacts_starting(self.db, first_name="random"))308 view.find_contacts_starting(self.db, first_name="random"))
@@ -317,7 +317,7 @@
317317
318 contacts = list(318 contacts = list(
319 view.find_contacts_exact(self.db, first_name="Frances"))319 view.find_contacts_exact(self.db, first_name="Frances"))
320 self.assertEqual(len(contacts), 1)320 self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,))
321321
322 contacts = list(view.find_contacts_exact(self.db, birth_date="-08-23"))322 contacts = list(view.find_contacts_exact(self.db, birth_date="-08-23"))
323 self.assertEqual(len(contacts), 1)323 self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,))

Subscribers

People subscribed via source and target branches