Merge lp:~verterok/ubuntuone-client/fix-645519-stable-1-4 into lp:ubuntuone-client

Proposed by Guillermo Gonzalez
Status: Rejected
Rejected by: dobey
Proposed branch: lp:~verterok/ubuntuone-client/fix-645519-stable-1-4
Merge into: lp:ubuntuone-client
Diff against target: 967 lines (+710/-23) (has conflicts)
9 files modified
contrib/testing/testcase.py (+2/-0)
nautilus/ubuntuone-nautilus.c (+410/-0)
tests/syncdaemon/test_action_queue.py (+50/-1)
tests/syncdaemon/test_dbus.py (+69/-0)
tests/syncdaemon/test_vm.py (+99/-11)
ubuntuone/syncdaemon/action_queue.py (+30/-0)
ubuntuone/syncdaemon/dbus_interface.py (+21/-11)
ubuntuone/syncdaemon/event_queue.py (+4/-0)
ubuntuone/syncdaemon/volume_manager.py (+25/-0)
Text conflict in nautilus/ubuntuone-nautilus.c
To merge this branch: bzr merge lp:~verterok/ubuntuone-client/fix-645519-stable-1-4
Reviewer Review Type Date Requested Status
dobey (community) Needs Resubmitting
Review via email: mp+36480@code.launchpad.net

Description of the change

This branch fix delete_share DBus method to actually delete shares (from_me), and mainting support for deleting share volumes (to me).

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

Wrong branch.

review: Needs Resubmitting

Unmerged revisions

718. By Guillermo Gonzalez

fix duplicated docstring

717. By Guillermo Gonzalez

Fix delete_share DBus method to actually delete shares

716. By Roman Yepishev

Reuse shared structure to avoid crashes due to referencing already released memory.

715. By John Lenton

correctly stringify http errors that occur in restclient (in another process), and fix the call to bus.get_object in the case of removing the current machine's token.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'contrib/testing/testcase.py'
2--- contrib/testing/testcase.py 2010-09-07 16:02:04 +0000
3+++ contrib/testing/testcase.py 2010-09-23 18:06:01 +0000
4@@ -145,6 +145,8 @@
5 """Send the event."""
6 self.eq.push('AQ_ANSWER_SHARE_OK', share_id, answer)
7
8+ def delete_share(self, share_id):
9+ """Stub."""
10
11 def disconnect(self, *a, **k):
12 """Stub implementation."""
13
14=== modified file 'nautilus/ubuntuone-nautilus.c'
15--- nautilus/ubuntuone-nautilus.c 2010-09-23 13:37:34 +0000
16+++ nautilus/ubuntuone-nautilus.c 2010-09-23 18:06:01 +0000
17@@ -328,6 +328,142 @@
18 iface->get_widget = ubuntuone_nautilus_get_location_widget;
19 }
20
21+<<<<<<< TREE
22+=======
23+static void __cb_data_free (struct _CBData * data, gboolean destroy) {
24+ if (!data)
25+ return;
26+
27+ data->uon = NULL;
28+ data->parent = NULL;
29+ data->make_public = FALSE;
30+
31+ if (data->path) {
32+ g_free (data->path);
33+ data->path = NULL;
34+ }
35+
36+ if (destroy) {
37+ g_free (data);
38+ data = NULL;
39+ }
40+
41+}
42+
43+/* Menu callbacks */
44+static void ubuntuone_nautilus_public_meta (SyncdaemonFilesystemInterface *interface,
45+ gboolean success,
46+ SyncdaemonMetadata *metadata,
47+ gpointer user_data) {
48+ struct _CBData * data = (struct _CBData *) user_data;
49+ GError * error = NULL;
50+ const gchar * share_id, * node_id;
51+ SyncdaemonInterface *public;
52+
53+ if (!success) {
54+ g_warning ("ERROR: getting metadata for public file");
55+ return;
56+ }
57+
58+ share_id = syncdaemon_metadata_get_share_id (metadata);
59+ node_id = syncdaemon_metadata_get_node_id (metadata);
60+
61+ public = syncdaemon_daemon_get_publicfiles_interface (data->uon->syncdaemon);
62+ if (public != NULL) {
63+ syncdaemon_publicfiles_interface_change_public_access (SYNCDAEMON_PUBLICFILES_INTERFACE (public),
64+ share_id, node_id, data->make_public);
65+ }
66+}
67+
68+static void ubuntuone_nautilus_unsubscribe_folder (NautilusMenuItem *item,
69+ gpointer user_data) {
70+ SyncdaemonInterface *interface;
71+ struct _CBData * data = (struct _CBData *) user_data;
72+
73+ /* Perform the removal of this folder */
74+ interface = syncdaemon_daemon_get_folders_interface (data->uon->syncdaemon);
75+ if (interface != NULL) {
76+ SyncdaemonFolderInfo *folder_info;
77+
78+ folder_info = syncdaemon_folders_interface_get_info (SYNCDAEMON_FOLDERS_INTERFACE (interface),
79+ data->path);
80+ if (folder_info != NULL) {
81+ if (ubuntuone_nautilus_check_shares_and_public_files (data->uon, folder_info, data->parent)) {
82+ syncdaemon_folders_interface_delete (SYNCDAEMON_FOLDERS_INTERFACE (interface),
83+ syncdaemon_folder_info_get_volume_id (folder_info));
84+ }
85+ g_object_unref (G_OBJECT (folder_info));
86+ }
87+ }
88+}
89+
90+static void ubuntuone_nautilus_subscribe_folder (NautilusMenuItem *item,
91+ gpointer user_data) {
92+ SyncdaemonInterface *interface;
93+ struct _CBData * data = (struct _CBData *) user_data;
94+
95+ /* Perform the addition of this folder */
96+ interface = syncdaemon_daemon_get_folders_interface (data->uon->syncdaemon);
97+ if (interface != NULL) {
98+ /* If there is no user authenticated, make Syncdaemon do so */
99+ if (!syncdaemon_authentication_has_credentials (syncdaemon_daemon_get_authentication (data->uon->syncdaemon)))
100+ syncdaemon_daemon_connect (data->uon->syncdaemon);
101+ syncdaemon_folders_interface_create (SYNCDAEMON_FOLDERS_INTERFACE (interface),
102+ data->path);
103+ }
104+}
105+
106+static void ubuntuone_nautilus_copy_public_url (NautilusMenuItem * item,
107+ gpointer user_data) {
108+ struct _CBData * data = (struct _CBData *) user_data;
109+ gchar * url;
110+
111+ url = g_hash_table_lookup (data->uon->public, data->path);
112+ gtk_clipboard_set_text (gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
113+ url, strlen (url));
114+ gtk_clipboard_store (gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
115+}
116+
117+static void ubuntuone_nautilus_toggle_publicity (NautilusMenuItem * item,
118+ gpointer user_data) {
119+ SyncdaemonFilesystemInterface *interface;
120+ struct _CBData * data = (struct _CBData *) user_data;
121+
122+ interface = (SyncdaemonFilesystemInterface *) syncdaemon_daemon_get_filesystem_interface (data->uon->syncdaemon);
123+ if (interface != NULL) {
124+ /* we know this will not be a directory (so no need for _and_quick_tree_synced) */
125+ syncdaemon_filesystem_interface_get_metadata_async (interface, data->path, FALSE,
126+ (SyncdaemonGotMetadataFunc) ubuntuone_nautilus_public_meta,
127+ data);
128+ }
129+
130+ g_hash_table_replace (data->uon->public, g_strdup (data->path), UPDATE_PENDING);
131+ ubuntuone_nautilus_reset_emblem (data->uon, data->path);
132+}
133+
134+static void ubuntuone_nautilus_share_folder (NautilusMenuItem * item,
135+ gpointer * user_data) {
136+ struct _CBData * data = (struct _CBData *) user_data;
137+ GtkWidget * dialog;
138+
139+ dialog = share_dialog_new (data->parent, data->uon, data->path);
140+ gtk_widget_show (dialog);
141+}
142+
143+static void ubuntuone_nautilus_unshare_folder (NautilusMenuItem * item,
144+ gpointer * user_data) {
145+ struct _CBData * data = (struct _CBData *) user_data;
146+ gchar * share_id;
147+ SyncdaemonSharesInterface *interface;
148+
149+ interface = (SyncdaemonSharesInterface *) syncdaemon_daemon_get_shares_interface (data->uon->syncdaemon);
150+ if (interface != NULL) {
151+ share_id = g_hash_table_lookup (data->uon->shares, data->path);
152+ syncdaemon_shares_interface_delete (interface, share_id);
153+ }
154+}
155+
156+>>>>>>> MERGE-SOURCE
157 /* Menu provider */
158 static GList *
159 ubuntuone_nautilus_get_menu_items (NautilusMenuProvider * provider,
160@@ -335,8 +471,20 @@
161 GList * files)
162 {
163 UbuntuOneNautilus * uon;
164+<<<<<<< TREE
165 GList *items = NULL;
166 NautilusMenuItem *root_item;
167+=======
168+ NautilusFileInfo * file;
169+ NautilusMenu * submenu;
170+ NautilusMenuItem * root_item;
171+ GList * items = NULL;
172+ gchar * path;
173+ gchar * item;
174+ gchar * homedir_path;
175+ gboolean is_managed, is_root, is_udf, is_public, is_shared, is_pending;
176+ gboolean is_inhome, is_dir, is_regular;
177+>>>>>>> MERGE-SOURCE
178
179 uon = UBUNTUONE_NAUTILUS (provider);
180
181@@ -344,9 +492,266 @@
182 if (!syncdaemon_daemon_is_ready (uon->syncdaemon))
183 return NULL;
184
185+<<<<<<< TREE
186 root_item = context_menu_new (uon, window, files);
187 if (root_item != NULL)
188 items = g_list_append (items, root_item);
189+=======
190+ is_managed = is_root = is_udf = is_public = is_shared = is_pending = FALSE;
191+ is_inhome = is_dir = is_regular = FALSE;
192+
193+ if (g_list_length (files) != 1)
194+ return NULL;
195+
196+ file = g_list_nth_data (files, 0);
197+ path = g_filename_from_uri (nautilus_file_info_get_uri (file), NULL, NULL);
198+
199+ if (path == NULL)
200+ goto done;
201+
202+ if (ubuntuone_is_storagefs (uon, path, &is_root))
203+ is_managed = TRUE;
204+
205+ homedir_path = g_strdup_printf ("%s/", g_get_home_dir());
206+ if (strncmp (path, homedir_path, strlen (homedir_path)) == 0)
207+ is_inhome = TRUE;
208+ g_free (homedir_path);
209+
210+ if ((item = g_hash_table_lookup (uon->udfs, path)) != NULL) {
211+ is_udf = TRUE;
212+ if (strcmp (item, UPDATE_PENDING) == 0)
213+ is_pending = TRUE;
214+ } else if ((item = g_hash_table_lookup (uon->public, path)) != NULL) {
215+ is_public = TRUE;
216+ if (strcmp (item, UPDATE_PENDING) == 0)
217+ is_pending = TRUE;
218+ }
219+ if (g_hash_table_lookup (uon->shares, path) != NULL)
220+ is_shared = TRUE;
221+
222+ is_dir = nautilus_file_info_is_directory (file);
223+ is_regular = nautilus_file_info_get_file_type (file) == G_FILE_TYPE_REGULAR;
224+
225+ /* Create new structure only if it does not already exist */
226+ if (uon->cb_data)
227+ __cb_data_free (uon->cb_data, FALSE);
228+ else
229+ uon->cb_data = g_new0 (struct _CBData, 1);
230+
231+ uon->cb_data->uon = uon;
232+ uon->cb_data->parent = window;
233+ uon->cb_data->path = g_strdup (path);
234+
235+ root_item = nautilus_menu_item_new ("ubuntuone",
236+ _("_Ubuntu One"),
237+ _("Ubuntu One options"),
238+ "ubuntuone");
239+ submenu = nautilus_menu_new ();
240+ nautilus_menu_item_set_submenu (root_item, submenu);
241+
242+ items = g_list_append (items, root_item);
243+
244+ /* Share/unshare */
245+ {
246+ NautilusMenuItem * item;
247+
248+ if ((is_managed || is_udf) && !is_root && is_dir) {
249+
250+ item = nautilus_menu_item_new ("ubuntuone-share",
251+ _("_Share..."),
252+ _("Share this folder on Ubuntu One"),
253+ "ubuntuone");
254+ if (is_pending)
255+ g_object_set (item, "sensitive", FALSE, NULL);
256+
257+ g_signal_connect (item, "activate",
258+ G_CALLBACK (ubuntuone_nautilus_share_folder),
259+ uon->cb_data);
260+ } else {
261+ /* the different tooltips will probably do us no good */
262+ if (is_root) {
263+ item = nautilus_menu_item_new ("ubuntuone-noshare-root",
264+ _("_Share..."),
265+ _("Sorry, you can't share the root of a Ubuntu One volume"),
266+ "ubuntuone");
267+ } else if (!(is_managed || is_udf)) {
268+ item = nautilus_menu_item_new ("ubuntuone-noshare-unmanaged",
269+ _("_Share..."),
270+ _("Sorry, you can't share folders not managed by Ubuntu One"),
271+ "ubuntuone");
272+ } else {
273+ item = nautilus_menu_item_new ("ubuntuone-noshare-unmanaged",
274+ _("_Share..."),
275+ _("Sorry, you can only share folders"),
276+ "ubuntuone");
277+ }
278+ g_object_set (item, "sensitive", FALSE, NULL);
279+ }
280+
281+ nautilus_menu_append_item (submenu, item);
282+ }
283+
284+ if ((is_managed && is_shared) && !is_root && is_dir) {
285+ NautilusMenuItem * item;
286+
287+ item = nautilus_menu_item_new ("ubuntuone-unshare",
288+ _("Stop _Sharing"),
289+ _("Stop sharing this folder on Ubuntu One"),
290+ "ubuntuone");
291+ if (is_pending)
292+ g_object_set (item, "sensitive", FALSE, NULL);
293+
294+ g_signal_connect (item, "activate",
295+ G_CALLBACK (ubuntuone_nautilus_unshare_folder),
296+ uon->cb_data);
297+ nautilus_menu_append_item (submenu, item);
298+ }
299+
300+ {
301+ /* UDF logic
302+ *
303+ * XXX: clean this up and separate the logic out and reuse this
304+ * and locationbar somewhere (libsd?)
305+ */
306+ NautilusMenuItem * item = NULL;
307+ if (is_dir && is_inhome) {
308+ /* UDFs could be happening */
309+ if (is_managed) {
310+ if (strcmp (path, uon->managed) == 0) {
311+ /* the Ubuntu One directory, no UDFs */
312+ item = nautilus_menu_item_new ("ubuntuone-no-disable-u1",
313+ _("Stop Synchronizing This _Folder"),
314+ _("Sorry, you can't stop synchronizing ~/Ubuntu One"),
315+ "ubuntuone");
316+ g_object_set (item, "sensitive", FALSE, NULL);
317+ } else if (is_root) {
318+ /* the root of a UDF: disabling possible */
319+
320+ item = nautilus_menu_item_new ("ubuntuone-disable-udf",
321+ _("Stop Synchronizing This _Folder"),
322+ _("Stop synchronizing this folder with Ubuntu One"),
323+ "ubuntuone");
324+
325+ g_signal_connect (item, "activate",
326+ G_CALLBACK (ubuntuone_nautilus_unsubscribe_folder),
327+ uon->cb_data);
328+ }
329+ } else {
330+ /* unmanaged */
331+
332+ item = nautilus_menu_item_new ("ubuntuone-enable-udf",
333+ _("Synchronize This _Folder"),
334+ _("Start synchronizing this folder with Ubuntu One"),
335+ "ubuntuone");
336+
337+ g_signal_connect (item, "activate",
338+ G_CALLBACK (ubuntuone_nautilus_subscribe_folder),
339+ uon->cb_data);
340+ }
341+ } else {
342+ if (is_dir) {
343+ item = nautilus_menu_item_new ("ubuntuone-no-disable-u1",
344+ _("Synchronize This _Folder"),
345+ _("Sorry, you can only synchronize folders within your home folder"),
346+ "ubuntuone");
347+ } else {
348+ item = nautilus_menu_item_new ("ubuntuone-no-disable-u1",
349+ _("Synchronize This _Folder"),
350+ _("Sorry, you can only synchronize folders"),
351+ "ubuntuone");
352+ }
353+ g_object_set (item, "sensitive", FALSE, NULL);
354+ }
355+ if (!item) {
356+ item = nautilus_menu_item_new ("ubuntuone-no-udf-operation-possible",
357+ _("Synchronize This _Folder"),
358+ _("Synchronization not possible for this folder"),
359+ "ubuntuone");
360+ g_object_set (item, "sensitive", FALSE, NULL);
361+ }
362+ nautilus_menu_append_item (submenu, item);
363+ }
364+
365+ /* public files */
366+ {
367+ NautilusMenuItem * item = NULL, * urlitem = NULL;
368+
369+ if (is_managed && is_regular) {
370+
371+ if (is_public) {
372+ urlitem = nautilus_menu_item_new ("ubuntuone-geturl",
373+ _("Copy Web _Link"),
374+ _("Copy the Ubuntu One public URL for this file to the clipboard."),
375+ "ubuntuone");
376+ if (is_pending)
377+ g_object_set (urlitem, "sensitive", FALSE, NULL);
378+
379+ g_signal_connect (urlitem, "activate",
380+ G_CALLBACK (ubuntuone_nautilus_copy_public_url),
381+ uon->cb_data);
382+ item = nautilus_menu_item_new ("ubuntuone-unpublish",
383+ _("Stop _Publishing"),
384+ _("No longer share this file with everyone via Ubuntu One."),
385+ "ubuntuone");
386+ if (is_pending)
387+ g_object_set (item, "sensitive", FALSE, NULL);
388+
389+ uon->cb_data->make_public = FALSE;
390+ } else {
391+ item = nautilus_menu_item_new ("ubuntuone-publish",
392+ _("_Publish"),
393+ _("Make this file available to anyone via Ubuntu One."),
394+ "ubuntuone");
395+ uon->cb_data->make_public = TRUE;
396+ }
397+ g_signal_connect (item, "activate",
398+ G_CALLBACK (ubuntuone_nautilus_toggle_publicity),
399+ uon->cb_data);
400+ }
401+ if (!urlitem) {
402+ urlitem = nautilus_menu_item_new ("ubuntuone-geturl",
403+ _("Copy Web _Link"),
404+ _("Sorry, no public URL for this file via Ubuntu One."),
405+ "ubuntuone");
406+ g_object_set (urlitem, "sensitive", FALSE, NULL);
407+ }
408+ if (!item) {
409+ item = nautilus_menu_item_new ("ubuntuone-publish",
410+ _("_Publish"),
411+ _("Sorry, unable to publish via Ubuntu One."),
412+ "ubuntuone");
413+ g_object_set (item, "sensitive", FALSE, NULL);
414+ }
415+
416+ nautilus_menu_append_item (submenu, item);
417+ nautilus_menu_append_item (submenu, urlitem);
418+ }
419+
420+ /* location bar enable/disable */
421+ {
422+ NautilusMenuItem * item;
423+ if (show_location()) {
424+ item = nautilus_menu_item_new ("ubuntuone-location-hide",
425+ _("Hide _Ribbon"),
426+ _("Do not show the Ubuntu One ribbon"
427+ " in selected folders"),
428+ "ubuntuone");
429+ } else {
430+ item = nautilus_menu_item_new ("ubuntuone-location-show",
431+ _("Show _Ribbon in Some Folders"),
432+ _("Show the Ubuntu One ribbon"
433+ " in selected folders"),
434+ "ubuntuone");
435+ }
436+ g_signal_connect (item, "activate",
437+ G_CALLBACK (toggle_location),
438+ uon->cb_data);
439+ nautilus_menu_append_item (submenu, item);
440+ }
441+
442+ done:
443+ g_free (path);
444+>>>>>>> MERGE-SOURCE
445
446 return items;
447 }
448@@ -439,6 +844,11 @@
449 static void ubuntuone_nautilus_finalize(GObject * object) {
450 UbuntuOneNautilus * uon = UBUNTUONE_NAUTILUS(object);
451
452+<<<<<<< TREE
453+=======
454+ __cb_data_free (uon->cb_data, TRUE);
455+
456+>>>>>>> MERGE-SOURCE
457 if (uon->syncdaemon)
458 g_object_unref (uon->syncdaemon);
459
460
461=== modified file 'tests/syncdaemon/test_action_queue.py'
462--- tests/syncdaemon/test_action_queue.py 2010-09-21 14:31:36 +0000
463+++ tests/syncdaemon/test_action_queue.py 2010-09-23 18:06:01 +0000
464@@ -51,7 +51,7 @@
465 ActionQueue, ActionQueueCommand, ChangePublicAccess, CreateUDF,
466 DeleteVolume, Download, ListVolumes,
467 NoisyRequestQueue, RequestQueue, UploadProgressWrapper, Upload,
468- CreateShare, GetPublicFiles, GetDelta, GetDeltaFromScratch,
469+ CreateShare, DeleteShare, GetPublicFiles, GetDelta, GetDeltaFromScratch,
470 TRANSFER_PROGRESS_THRESHOLD, Unlink, Move, MakeFile, MakeDir,
471 DeltaList, ZipQueue, DeferredMap, UniqueRequestQueue
472 )
473@@ -64,6 +64,7 @@
474 VOLUME = uuid.UUID('12345678-1234-1234-1234-123456789abc')
475 NODE = uuid.UUID('FEDCBA98-7654-3211-2345-6789ABCDEF12')
476 USER = u'Dude'
477+SHARE = uuid.uuid4()
478
479 NO_OP = lambda *args, **kwargs: None
480
481@@ -2680,6 +2681,54 @@
482 self.assertEqual(len(self.queue), 0)
483
484
485+class DeleteShareTestCase(ConnectedBaseTestCase):
486+ """Test for DeleteShare ActionQueueCommand."""
487+
488+ @defer.inlineCallbacks
489+ def setUp(self):
490+ """Init."""
491+ yield super(DeleteShareTestCase, self).setUp()
492+ request_queue = RequestQueue(name='fu', action_queue=self.action_queue)
493+ self.command = DeleteShare(request_queue, SHARE)
494+ vm = self.action_queue.main.vm
495+ self.patch(vm, 'handle_AQ_DELETE_SHARE_OK', NO_OP)
496+ self.patch(vm, 'handle_AQ_DELETE_SHARE_ERROR', NO_OP)
497+
498+ def test_run_returns_a_deferred(self):
499+ """Test a deferred is returned."""
500+ res = self.command._run()
501+ self.assertTrue(isinstance(res, defer.Deferred), 'deferred returned')
502+
503+ def test_run_calls_protocol(self):
504+ """Test protocol's delete_volume is called."""
505+ self.called = False
506+ def check(share_id):
507+ """Take control over client's feature."""
508+ self.called = True
509+ self.assertEqual(SHARE, share_id)
510+ self.patch(self.command.action_queue.client, 'delete_share', check)
511+ self.command._run()
512+ self.assertTrue(self.called, "command wasn't called")
513+
514+ def test_handle_success_push_event(self):
515+ """Test AQ_DELETE_SHARE_OK is pushed on success."""
516+ request = client.DeleteShare(self.action_queue.client, SHARE)
517+ res = self.command.handle_success(success=request)
518+ events = [('AQ_DELETE_SHARE_OK', (), {'share_id': SHARE})]
519+ self.assertEqual(events, self.command.action_queue.event_queue.events)
520+ self.assertEqual(request, res)
521+
522+ def test_handle_failure_push_event(self):
523+ """Test AQ_DELETE_SHARE_ERROR is pushed on failure."""
524+ msg = 'Something went wrong'
525+ failure = Failure(DefaultException(msg))
526+ res = self.command.handle_failure(failure=failure)
527+ events = [('AQ_DELETE_SHARE_ERROR', (),
528+ {'share_id': SHARE, 'error': msg})]
529+ self.assertEqual(events, self.command.action_queue.event_queue.events)
530+ self.assertTrue(res is None)
531+
532+
533 class SimpleAQTestCase(BasicTestCase):
534 """Simple tests for AQ API."""
535
536
537=== modified file 'tests/syncdaemon/test_dbus.py'
538--- tests/syncdaemon/test_dbus.py 2010-09-13 16:55:35 +0000
539+++ tests/syncdaemon/test_dbus.py 2010-09-23 18:06:01 +0000
540@@ -2885,6 +2885,31 @@
541 error_handler=self.error_handler)
542 return d
543
544+ def test_delete_share_from_me(self):
545+ """Test for Shares.delete_share with share from_me."""
546+ share_path = os.path.join(self.main.shares_dir, 'share')
547+ share = Shared(path=share_path, volume_id='share_id',
548+ node_id='node_id', accepted=True)
549+ self.main.vm.add_shared(share)
550+ d = defer.Deferred()
551+ def delete_share(volume_id):
552+ """Fake delete_volume."""
553+ self.main.event_q.push("AQ_DELETE_SHARE_OK", share_id=volume_id)
554+ self.patch(self.main.action_q, 'delete_share', delete_share)
555+ def deleted_handler(info):
556+ """ShareDeleted handler."""
557+ self.assertRaises(KeyError,
558+ self.main.vm.shared.__getitem__, info['volume_id'])
559+ d.callback(True)
560+ match = self.bus.add_signal_receiver(deleted_handler,
561+ signal_name='ShareDeleted')
562+ self.signal_receivers.add(match)
563+ client = DBusClient(self.bus, '/shares', DBUS_IFACE_SHARES_NAME)
564+ client.call_method('delete_share', share.volume_id,
565+ reply_handler=lambda _: None,
566+ error_handler=self.error_handler)
567+ return d
568+
569 def test_delete_share_error_signal(self):
570 """Test for Shares.delete_share with an error."""
571 share_path = os.path.join(self.main.shares_dir, 'share')
572@@ -2912,6 +2937,50 @@
573 error_handler=self.error_handler)
574 return d
575
576+ def test_delete_share_from_me_error(self):
577+ """Test failure of Shares.delete_share with a share from_me."""
578+ share_path = os.path.join(self.main.shares_dir, 'share')
579+ share = Shared(path=share_path, volume_id='share_id',
580+ node_id='node_id', accepted=True)
581+ self.main.vm.add_shared(share)
582+ d = defer.Deferred()
583+ # patch delete_share to fail
584+ def delete_share(share_id):
585+ """Fake delete_share."""
586+ self.main.event_q.push("AQ_DELETE_SHARE_ERROR",
587+ share_id=share_id, error="I'm broken")
588+ self.patch(self.main.action_q, 'delete_share', delete_share)
589+ def deleted_error_handler(info, error):
590+ """FolderDeleteError handler."""
591+ self.assertEquals(info['volume_id'], share.volume_id)
592+ self.assertEquals(error, "I'm broken")
593+ d.callback(True)
594+ match = self.bus.add_signal_receiver(deleted_error_handler,
595+ signal_name='ShareDeleteError')
596+ self.signal_receivers.add(match)
597+ client = DBusClient(self.bus, '/shares', DBUS_IFACE_SHARES_NAME)
598+ client.call_method('delete_share', share.volume_id,
599+ reply_handler=lambda *args: None,
600+ error_handler=self.error_handler)
601+ return d
602+
603+ def test_delete_share_from_me_doesnotexist(self):
604+ """Test failure of Shares.delete_share with a share from_me."""
605+ d = defer.Deferred()
606+ # patch delete_share to fail
607+ def deleted_error_handler(info, error):
608+ """FolderDeleteError handler."""
609+ self.assertEquals(info['volume_id'], 'missing_share_id')
610+ self.assertEquals(error, "DOES_NOT_EXIST")
611+ d.callback(True)
612+ match = self.bus.add_signal_receiver(deleted_error_handler,
613+ signal_name='ShareDeleteError')
614+ self.signal_receivers.add(match)
615+ client = DBusClient(self.bus, '/shares', DBUS_IFACE_SHARES_NAME)
616+ client.call_method('delete_share', 'missing_share_id',
617+ reply_handler=lambda *args: None,
618+ error_handler=self.error_handler)
619+ return d
620
621 def test_suite():
622 # pylint: disable-msg=C0111
623
624=== modified file 'tests/syncdaemon/test_vm.py'
625--- tests/syncdaemon/test_vm.py 2010-09-16 20:38:05 +0000
626+++ tests/syncdaemon/test_vm.py 2010-09-23 18:06:01 +0000
627@@ -412,6 +412,63 @@
628 share = self.vm.shared[str(expected_share_id)]
629 self.assertEquals(str(expected_node_id), share.node_id)
630
631+ @defer.inlineCallbacks
632+ def test_delete_shared(self):
633+ """Test VolumeManager.delete_share."""
634+ path = os.path.join(self.vm.root.path, 'shared_path')
635+ self.main.fs.create(path, "")
636+ self.main.fs.set_node_id(path, 'node_id')
637+ share = Shared(path=path, volume_id='share_id', node_id="node_id")
638+ self.vm.add_shared(share)
639+
640+ def fake_delete_share(share_id):
641+ """Fake delete_share."""
642+ self.assertEqual(share_id, share.volume_id)
643+ self.main.event_q.push('AQ_DELETE_SHARE_OK', share_id)
644+
645+ self.patch(self.main.action_q, 'delete_share', fake_delete_share)
646+ d = defer.Deferred()
647+ self._listen_for('VM_SHARE_DELETED', d.callback, 1, collect=True)
648+ self.vm.delete_share(share.volume_id)
649+ events = yield d
650+ event = events[0]
651+ self.assertEqual(event[0], (share,))
652+
653+ @defer.inlineCallbacks
654+ def test_delete_shared_error(self):
655+ """Test VolumeManager.delete_share."""
656+ path = os.path.join(self.vm.root.path, 'shared_path')
657+ self.main.fs.create(path, "")
658+ self.main.fs.set_node_id(path, 'node_id')
659+ share = Shared(path=path, volume_id='share_id', node_id="node_id")
660+ self.vm.add_shared(share)
661+
662+ def fake_delete_share(share_id):
663+ """Fake delete_share that always fails."""
664+ self.main.event_q.push('AQ_DELETE_SHARE_ERROR',
665+ share_id, 'a fake error')
666+
667+ self.patch(self.main.action_q, 'delete_share', fake_delete_share)
668+ d = defer.Deferred()
669+ self._listen_for('VM_SHARE_DELETE_ERROR', d.callback, 1, collect=True)
670+ self.vm.delete_share(share.volume_id)
671+ events = yield d
672+ event = events[0]
673+ self.assertEqual(event[0], (share.volume_id, 'a fake error'))
674+
675+ @defer.inlineCallbacks
676+ def test_delete_shared_error_missing_share(self):
677+ """Test VolumeManager.delete_share with a non-existent share."""
678+ path = os.path.join(self.vm.root.path, 'shared_path')
679+ self.main.fs.create(path, "")
680+ self.main.fs.set_node_id(path, 'node_id')
681+ d = defer.Deferred()
682+ self._listen_for('VM_SHARE_DELETE_ERROR', d.callback, 1, collect=True)
683+ self.vm.delete_share('fake_share_id')
684+ events = yield d
685+ event = events[0]
686+ self.assertEqual(event[0], ('fake_share_id', 'DOES_NOT_EXIST'))
687+
688 def test_accept_share(self):
689 """ Test the accept_share method. """
690 d = defer.Deferred()
691@@ -680,6 +737,38 @@
692 self.assertTrue(os.path.exists(share.path),
693 'share path missing on disk!')
694
695+ @defer.inlineCallbacks
696+ def test_handle_AQ_DELETE_SHARE_OK(self):
697+ """Test for handle_AQ_DELETE_SHARE_OK."""
698+ """Test VolumeManager.delete_share."""
699+ path = os.path.join(self.vm.root.path, 'shared_path')
700+ self.main.fs.create(path, "")
701+ self.main.fs.set_node_id(path, 'node_id')
702+ share = Shared(path=path, volume_id='share_id', node_id="node_id")
703+ self.vm.add_shared(share)
704+ d = defer.Deferred()
705+ self._listen_for('VM_SHARE_DELETED', d.callback, 1, collect=True)
706+ self.main.event_q.push('AQ_DELETE_SHARE_OK', 'share_id')
707+ events = yield d
708+ event = events[0]
709+ self.assertEqual(event[0], (share,))
710+
711+ @defer.inlineCallbacks
712+ def test_handle_AQ_DELETE_SHARE_ERROR(self):
713+ """Test for handle_AQ_DELETE_SHARE_ERROR."""
714+ path = os.path.join(self.vm.root.path, 'shared_path')
715+ self.main.fs.create(path, "")
716+ self.main.fs.set_node_id(path, 'node_id')
717+ share = Shared(path=path, volume_id='share_id', node_id="node_id")
718+ self.vm.add_shared(share)
719+ d = defer.Deferred()
720+ self._listen_for('VM_SHARE_DELETE_ERROR', d.callback, 1, collect=True)
721+ self.main.event_q.push('AQ_DELETE_SHARE_ERROR',
722+ 'share_id', 'a fake error')
723+ events = yield d
724+ event = events[0]
725+ self.assertEqual(event[0], (share.volume_id, 'a fake error'))
726+
727
728 class VolumeManagerUnicodeTests(BaseVolumeManagerTests):
729 """Tests for Volume Manager unicode capabilities."""
730@@ -1008,8 +1097,8 @@
731 """Test the handling of the AQ_LIST_VOLUMES event."""
732 share_id = uuid.uuid4()
733 share_volume = volumes.ShareVolume(share_id, 'fake_share_uuid', None,
734- 10, 'to_me', u'ñoño'.encode("utf8"),
735- 'username', 'visible_username',
736+ 10, 'to_me', u'ñoño',
737+ 'username', u'visible_username',
738 True, 'View')
739 udf_id = uuid.uuid4()
740 udf_volume = volumes.UDFVolume(udf_id, 'udf_uuid', None, 10, u'~/ñoño')
741@@ -1028,7 +1117,7 @@
742 self.assertIn(str(share_id), self.vm.shares)
743 self.assertIn(str(udf_id), self.vm.udfs)
744 share = self.vm.shares[str(share_id)]
745- self.assertEqual(u'ñoño'.encode("utf8"), share.name)
746+ self.assertEqual(u'ñoño', share.name)
747 self.assertEqual('fake_share_uuid', share.node_id)
748 udf = self.vm.udfs[str(udf_id)]
749 self.assertEqual('udf_uuid', udf.node_id)
750@@ -1140,8 +1229,8 @@
751 yield self.vm.add_udf(udf)
752 share_id = uuid.uuid4()
753 share_volume = volumes.ShareVolume(share_id, 'fake_share_uuid', None,
754- 10, 'to_me', u'ñoño'.encode("utf8"),
755- 'username', 'visible_username',
756+ 10, 'to_me', u'ñoño',
757+ 'username', u'visible_username',
758 True, 'View')
759 dir_name = self.vm._build_share_path(share_volume.share_name,
760 share_volume.other_visible_name)
761@@ -1604,8 +1693,8 @@
762 udf_volume = volumes.UDFVolume(udf_id, 'udf_uuid', None, 10, u'~/ñoño')
763 share_id = uuid.uuid4()
764 share_volume = volumes.ShareVolume(share_id, 'fake_share_uuid', None,
765- 10, 'to_me', u'ñoño'.encode("utf8"),
766- 'username', 'visible_username',
767+ 10, 'to_me', u'ñoño',
768+ 'username', u'visible_username',
769 True, 'View')
770 # initialize the the root
771 self.vm._got_root('root_uuid')
772@@ -1656,8 +1745,8 @@
773 """Test for handle_SV_VOLUME_DELETED."""
774 share_id = uuid.uuid4()
775 share_volume = volumes.ShareVolume(share_id, 'fake_share_uuid', None,
776- 10, 'to_me', u'ñoño'.encode("utf8"),
777- 'username', 'visible_username',
778+ 10, 'to_me', u'ñoño',
779+ 'username', u'visible_username',
780 True, 'View')
781 dir_name = self.vm._build_share_path(share_volume.share_name,
782 share_volume.other_visible_name)
783@@ -1665,8 +1754,7 @@
784 share = Share.from_share_volume(share_volume, share_path)
785 # create a UDF
786 udf_id = uuid.uuid4()
787- udf, udf_volume = self._create_udf(udf_id, 'udf_uuid',
788- u'~/ñoño'.encode("utf8"))
789+ udf, udf_volume = self._create_udf(udf_id, 'udf_uuid', u'~/ñoño')
790 yield self.vm.add_udf(udf)
791 self.vm.add_share(share)
792 # initialize the the root
793
794=== modified file 'ubuntuone/syncdaemon/action_queue.py'
795--- ubuntuone/syncdaemon/action_queue.py 2010-09-21 14:31:36 +0000
796+++ ubuntuone/syncdaemon/action_queue.py 2010-09-23 18:06:01 +0000
797@@ -1002,6 +1002,10 @@
798 return CreateShare(self.meta_queue, node_id, share_to, name,
799 access_level, marker).queue()
800
801+ def delete_share(self, share_id):
802+ """Delete a offered share."""
803+ return DeleteShare(self.meta_queue, share_id).queue()
804+
805 def create_udf(self, path, name, marker):
806 """Create a User Defined Folder.
807
808@@ -1689,6 +1693,32 @@
809 error=failure.getErrorMessage())
810
811
812+class DeleteShare(ActionQueueCommand):
813+ """Delete a offered Share."""
814+
815+ __slots__ = ('share_id',)
816+
817+ def __init__(self, request_queue, share_id):
818+ super(DeleteShare, self).__init__(request_queue)
819+ self.share_id = share_id
820+
821+ def _run(self):
822+ """Do the actual running."""
823+ return self.action_queue.client.delete_share(self.share_id)
824+
825+ def handle_success(self, success):
826+ """It worked! Push the event."""
827+ self.action_queue.event_queue.push('AQ_DELETE_SHARE_OK',
828+ share_id=self.share_id)
829+ return success
830+
831+ def handle_failure(self, failure):
832+ """It didn't work. Push the event."""
833+ self.action_queue.event_queue.push('AQ_DELETE_SHARE_ERROR',
834+ share_id=self.share_id,
835+ error=failure.getErrorMessage())
836+
837+
838 class CreateUDF(ActionQueueCommand):
839 """Create a new User Defined Folder."""
840
841
842=== modified file 'ubuntuone/syncdaemon/dbus_interface.py'
843--- ubuntuone/syncdaemon/dbus_interface.py 2010-09-16 16:54:48 +0000
844+++ ubuntuone/syncdaemon/dbus_interface.py 2010-09-23 18:06:01 +0000
845@@ -788,6 +788,16 @@
846 self.handle_default('VM_SHARE_CREATED', share_id)
847 self.dbus_iface.shares.emit_new_share(share_id)
848
849+ def handle_VM_SHARE_DELETED(self, share):
850+ """Handle VM_SHARE_DELETED event, emit NewShare event."""
851+ self.handle_default('VM_SHARE_DELETED', getattr(share, 'id', share))
852+ self.dbus_iface.shares.emit_share_changed('deleted', share)
853+
854+ def handle_VM_SHARE_DELETE_ERROR(self, share_id, error):
855+ """Handle VM_DELETE_SHARE_ERROR event, emit ShareCreateError signal."""
856+ self.handle_default('VM_SHARE_DELETE_ERROR', share_id, error)
857+ self.dbus_iface.shares.ShareDeleteError(dict(volume_id=share_id), error)
858+
859 def handle_VM_VOLUME_DELETED(self, volume):
860 """Handle VM_VOLUME_DELETED event.
861
862@@ -804,7 +814,7 @@
863 "volume_id=%r as it's not a share or UDF", volume.id)
864
865 def handle_VM_VOLUME_DELETE_ERROR(self, volume_id, error):
866- """Handle VM_SHARE_DELETED event, emit ShareDeleted event."""
867+ """Handle VM_VOLUME_DELETE_ERROR event, emit ShareDeleted event."""
868 self.handle_default('VM_VOLUME_DELETE_ERROR', volume_id, error)
869 try:
870 volume = self.dbus_iface.volume_manager.get_volume(volume_id)
871@@ -1131,21 +1141,21 @@
872 str(share_id)))
873
874 @dbus.service.method(DBUS_IFACE_SHARES_NAME,
875- in_signature='s', out_signature='',
876- async_callbacks=('reply_handler', 'error_handler'))
877- def delete_share(self, share_id, reply_handler=None, error_handler=None):
878- """Delete a Share."""
879+ in_signature='s', out_signature='')
880+ def delete_share(self, share_id):
881+ """Delete a Share, both kinds: "to me" and "from me"."""
882 logger.debug('delete_share: %r', share_id)
883 try:
884- self.vm.delete_volume(str(share_id))
885- reply_handler()
886- except VolumeDoesNotExist, e:
887- self.ShareDeleteError({'volume_id':share_id}, str(e))
888+ try:
889+ self.vm.delete_volume(str(share_id))
890+ except VolumeDoesNotExist:
891+ # isn't a volume! it might be a "share from me (a.k.a shared)"
892+ self.vm.delete_share(str(share_id))
893 except Exception, e:
894- error_handler(e)
895 logger.exception('Error while deleting share: %r', share_id)
896 self.ShareDeleteError({'volume_id':share_id}, str(e))
897-
898+ # propagate the error
899+ raise
900
901 @dbus.service.signal(DBUS_IFACE_SHARES_NAME,
902 signature='a{ss}')
903
904=== modified file 'ubuntuone/syncdaemon/event_queue.py'
905--- ubuntuone/syncdaemon/event_queue.py 2010-08-31 14:19:53 +0000
906+++ ubuntuone/syncdaemon/event_queue.py 2010-09-23 18:06:01 +0000
907@@ -69,6 +69,8 @@
908 'AQ_LIST_SHARES_ERROR': ('error',),
909 'AQ_CREATE_SHARE_OK': ('share_id', 'marker'),
910 'AQ_CREATE_SHARE_ERROR': ('marker', 'error'),
911+ 'AQ_DELETE_SHARE_OK': ('share_id',),
912+ 'AQ_DELETE_SHARE_ERROR': ('share_id', 'error'),
913 'AQ_QUERY_ERROR': ('item', 'error'),
914 'AQ_ANSWER_SHARE_OK': ('share_id', 'answer'),
915 'AQ_ANSWER_SHARE_ERROR': ('share_id', 'answer', 'error'),
916@@ -145,6 +147,8 @@
917 'VM_UDF_CREATED': ('udf',),
918 'VM_UDF_CREATE_ERROR': ('path', 'error'),
919 'VM_SHARE_CREATED': ('share_id',),
920+ 'VM_SHARE_DELETED': ('udf',),
921+ 'VM_SHARE_DELETE_ERROR': ('path', 'error'),
922 'VM_VOLUME_DELETED': ('volume',),
923 'VM_VOLUME_DELETE_ERROR': ('volume_id', 'error'),
924 'VM_SHARE_CHANGED': ('share_id',),
925
926=== modified file 'ubuntuone/syncdaemon/volume_manager.py'
927--- ubuntuone/syncdaemon/volume_manager.py 2010-09-16 20:38:05 +0000
928+++ ubuntuone/syncdaemon/volume_manager.py 2010-09-23 18:06:01 +0000
929@@ -717,6 +717,22 @@
930 if marker in self.marker_share_map:
931 del self.marker_share_map[marker]
932
933+ def handle_AQ_DELETE_SHARE_OK(self, share_id):
934+ """Handle AQ_DELETE_SHARE_OK event."""
935+ share = self.shared.get(share_id)
936+ if share is not None:
937+ del self.shared[share_id]
938+ self.m.event_q.push('VM_SHARE_DELETED', share)
939+ else:
940+ # delete ok, of something we don't have.
941+ self.log.warning("AQ_DELETE_SHARE_OK of a non-existing shared "
942+ "dir: %s", share_id)
943+
944+ def handle_AQ_DELETE_SHARE_ERROR(self, share_id, error):
945+ """Gandle AQ_DELETE_SHARE_ERROR event."""
946+ self.log.error("Error while deleting offered share: %s", error)
947+ self.m.event_q.push('VM_SHARE_DELETE_ERROR', share_id, error)
948+
949 def handle_SV_SHARE_ANSWERED(self, share_id, answer):
950 """ handle SV_SHARE_ANSWERED event. """
951 share = self.shared.get(share_id, None)
952@@ -908,6 +924,15 @@
953 self.m.action_q.create_share(node_id, username, name,
954 access_level, marker)
955
956+ def delete_share(self, share_id):
957+ """Reuqest the deletion of an offered share."""
958+ share = self.shared.get(share_id)
959+ if share is None:
960+ # if the share isn't there, push the error!
961+ self.m.event_q.push('VM_SHARE_DELETE_ERROR', share_id, "DOES_NOT_EXIST")
962+ else:
963+ self.m.action_q.delete_share(share_id)
964+
965 def add_shared(self, share):
966 """ Add a share with direction == from_me """
967 self.log.info('New shared subtree: id: %s - path: %r',

Subscribers

People subscribed via source and target branches