~hadware/magicicada-server/trusty-support

« back to all changes in this revision

Viewing changes to src/server/tests/test_sharing.py

  • Committer: Facundo Batista
  • Date: 2015-08-05 13:10:02 UTC
  • Revision ID: facundo@taniquetil.com.ar-20150805131002-he7b7k704d8o7js6
First released version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2008-2015 Canonical
 
2
#
 
3
# This program is free software: you can redistribute it and/or modify
 
4
# it under the terms of the GNU Affero General Public License as
 
5
# published by the Free Software Foundation, either version 3 of the
 
6
# License, or (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU Affero General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU Affero General Public License
 
14
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 
15
#
 
16
# For further info, check  http://launchpad.net/filesync-server
 
17
 
 
18
"""Test sharing operations."""
 
19
 
 
20
import uuid
 
21
import zlib
 
22
 
 
23
from StringIO import StringIO
 
24
 
 
25
from twisted.internet import reactor, defer
 
26
 
 
27
from backends.filesync.data import errors, dbmanager, model
 
28
from ubuntuone.storage.server.testing.testcase import (
 
29
    TestWithDatabase, FactoryHelper)
 
30
from ubuntuone.storageprotocol import request
 
31
from ubuntuone.storageprotocol import errors as protocol_errors
 
32
from ubuntuone.storageprotocol.content_hash import content_hash_factory, crc32
 
33
 
 
34
EMPTY_HASH = content_hash_factory().content_hash()
 
35
NO_CONTENT_HASH = ""
 
36
 
 
37
 
 
38
class TestCreateShare(TestWithDatabase):
 
39
    """Test crate_share command."""
 
40
 
 
41
    def test_delete_share(self):
 
42
        """Test deletion of an offered by me share."""
 
43
 
 
44
        @defer.inlineCallbacks
 
45
        def _do_delete(client):
 
46
            """Callback to do delete."""
 
47
            # authenticate and create a root to share
 
48
            yield client.dummy_authenticate("open sesame")
 
49
            root = yield client.get_root()
 
50
            res = yield client.create_share(root, self.usr1.username,
 
51
                                            u"name", "View")
 
52
            share_id = uuid.UUID(res.share_id)
 
53
            yield client.delete_share(share_id)
 
54
            self.assertRaises(errors.DoesNotExist,
 
55
                              self.usr1.get_share, share_id)
 
56
            client.test_done()
 
57
 
 
58
        def do_delete(client):
 
59
            """Test body callback."""
 
60
            d = _do_delete(client)
 
61
            d.addErrback(client.test_fail)
 
62
 
 
63
        return self.callback_test(do_delete)
 
64
 
 
65
    def test_delete_volume(self):
 
66
        """Test deletion of an offered to me and accepted share."""
 
67
 
 
68
        def create_share(_):
 
69
            share = self.usr1.root.share(self.usr0.id, u"sharename",
 
70
                                         readonly=True)
 
71
            self.usr0.get_share(share.id).accept()
 
72
            return share
 
73
 
 
74
        def auth(client):
 
75
            # authenticate and create the share
 
76
            d = client.dummy_authenticate("open sesame")
 
77
            d.addCallback(create_share)
 
78
 
 
79
            # delete the share and check
 
80
            d.addCallback(lambda share: client.delete_volume(share.id))
 
81
            d.addCallbacks(client.test_done, client.test_fail)
 
82
 
 
83
        return self.callback_test(auth)
 
84
 
 
85
    def test_create_view(self):
 
86
        """Create a share using View."""
 
87
 
 
88
        def auth(client):
 
89
            def verifyDB():
 
90
                reg = self.usr1.get_shared_to()[0]
 
91
                self.assertEqual(reg.name, "name")
 
92
                self.assertEqual(reg.access, "View")
 
93
 
 
94
            # authenticate and create a root to share
 
95
            d = client.dummy_authenticate("open sesame")
 
96
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
97
 
 
98
            # create the share
 
99
            d.addCallbacks(
 
100
                lambda r: client.create_share(
 
101
                    r, self.usr1.username, u"name", "View"),
 
102
                client.test_fail)
 
103
 
 
104
            d.addCallback(lambda _: verifyDB())
 
105
 
 
106
            d.addCallbacks(client.test_done, client.test_fail)
 
107
 
 
108
        return self.callback_test(auth)
 
109
 
 
110
    def test_create_basic_modify(self):
 
111
        """Create a share using Modify."""
 
112
 
 
113
        def auth(client):
 
114
            # authenticate and create a root to share
 
115
            d = client.dummy_authenticate("open sesame")
 
116
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
117
 
 
118
            # create the share
 
119
            d.addCallbacks(
 
120
                lambda r: client.create_share(
 
121
                    r, self.usr1.username, u"name", "Modify"),
 
122
                client.test_fail)
 
123
 
 
124
            d.addCallbacks(client.test_done, client.test_fail)
 
125
 
 
126
        return self.callback_test(auth)
 
127
 
 
128
    def test_create_usr_twice(self):
 
129
        """Create a share that tries to share twice same node to same user."""
 
130
 
 
131
        def auth(client):
 
132
            # authenticate and create a root to share
 
133
            d = client.dummy_authenticate("open sesame")
 
134
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
135
 
 
136
            # create the share
 
137
            d.addCallbacks(
 
138
                lambda r: client.create_share(
 
139
                    r, self.usr1.username, u"name1", "Modify"),
 
140
                client.test_fail)
 
141
 
 
142
            # create a share of the same node to the same user
 
143
            d.addCallbacks(
 
144
                lambda r: client.create_share(
 
145
                    r, self.usr1.username, u"name2", "Modify"),
 
146
                client.test_fail)
 
147
 
 
148
            d.addCallbacks(client.test_fail, lambda x: client.test_done("ok"))
 
149
 
 
150
        return self.callback_test(auth)
 
151
 
 
152
    def test_create_same_name_different_user(self):
 
153
        """Create two shares repeating the name but changing the user."""
 
154
 
 
155
        def auth(client):
 
156
            # authenticate and create a root to share
 
157
            d = client.dummy_authenticate("open sesame")
 
158
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
159
            d.addCallback(self.save_req, 'root_id')
 
160
 
 
161
            # create the share to one user
 
162
            d.addCallbacks(
 
163
                lambda r: client.create_share(self._state.root_id,
 
164
                                              self.usr1.username,
 
165
                                              u"same name", "View"),
 
166
                client.test_fail)
 
167
 
 
168
            # create the share to other user
 
169
            d.addCallbacks(
 
170
                lambda r: client.create_share(self._state.root_id,
 
171
                                              self.usr2.username,
 
172
                                              u"same name", "View"),
 
173
                client.test_fail)
 
174
 
 
175
            d.addCallbacks(client.test_done, client.test_fail)
 
176
 
 
177
        return self.callback_test(auth)
 
178
 
 
179
    def test_create_different_name_same_user(self):
 
180
        """Create two shares repeating the name but changing the user."""
 
181
 
 
182
        def auth(client):
 
183
            # authenticate and create a root to share
 
184
            d = client.dummy_authenticate("open sesame")
 
185
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
186
            d.addCallback(self.save_req, 'root_id')
 
187
 
 
188
            # create other directory to share
 
189
            d.addCallbacks(
 
190
                lambda r: client.make_dir(request.ROOT, r, "hola"),
 
191
                client.test_fail)
 
192
 
 
193
            # create the share using the just created directory
 
194
            d.addCallbacks(
 
195
                lambda r: client.create_share(r.new_id,
 
196
                                              self.usr1.username,
 
197
                                              u"new dir", "View"),
 
198
                client.test_fail)
 
199
 
 
200
            # create the share using root
 
201
            d.addCallbacks(
 
202
                lambda r: client.create_share(self._state.root_id,
 
203
                                              self.usr1.username,
 
204
                                              u"root dir", "View"),
 
205
                client.test_fail)
 
206
 
 
207
            d.addCallbacks(client.test_done, client.test_fail)
 
208
 
 
209
        return self.callback_test(auth)
 
210
 
 
211
    def test_create_same_name_same_user(self):
 
212
        """Create two shares repeating the name and the user."""
 
213
        @defer.inlineCallbacks
 
214
        def test(client):
 
215
            """Test."""
 
216
            # authenticate and create a root to share
 
217
            yield client.dummy_authenticate("open sesame")
 
218
            root_id = yield client.get_root()
 
219
 
 
220
            # create other directory to share
 
221
            makedir_req = yield client.make_dir(request.ROOT, root_id, u"hola")
 
222
 
 
223
            # create the share using the just created directory
 
224
            yield client.create_share(makedir_req.new_id, self.usr1.username,
 
225
                                      u"same_name", "View")
 
226
 
 
227
            # create the share using root
 
228
            d = client.create_share(root_id, self.usr1.username,
 
229
                                    u"same_name", "View")
 
230
 
 
231
            # the last call must fail with AlreadyExist
 
232
            yield self.assertFailure(d, protocol_errors.AlreadyExistsError)
 
233
 
 
234
        return self.callback_test(test, add_default_callbacks=True)
 
235
 
 
236
    def test_create_share_file(self):
 
237
        """Create a share on a file."""
 
238
 
 
239
        def auth(client):
 
240
            # authenticate and create a root to share
 
241
            d = client.dummy_authenticate("open sesame")
 
242
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
243
 
 
244
            # create the file to share
 
245
            d.addCallbacks(
 
246
                lambda r: client.make_file(request.ROOT, r, "hola"),
 
247
                client.test_fail)
 
248
 
 
249
            # create the share
 
250
            d.addCallbacks(
 
251
                lambda r: client.create_share(r.new_id, self.usr1.username,
 
252
                                              u"foo", "Modify"),
 
253
                client.test_fail)
 
254
 
 
255
            d.addCallbacks(client.test_fail, lambda x: client.test_done("ok"))
 
256
 
 
257
        return self.callback_test(auth)
 
258
 
 
259
    def test_notify_creation_to_myself(self):
 
260
        """Create a share to myself and listen to the notification."""
 
261
 
 
262
        def auth(client):
 
263
            def notif(share_notif):
 
264
                self.assertEqual(
 
265
                    share_notif.subtree, str(self._state.root_id))
 
266
                self.assertEqual(share_notif.share_name, "name")
 
267
                self.assertEqual(share_notif.from_username,
 
268
                                 self.usr0.username)
 
269
                self.assertEqual(share_notif.from_visible_name,
 
270
                                 self.usr0.visible_name)
 
271
                self.assertEqual(share_notif.access_level, "View")
 
272
                client.test_done()
 
273
 
 
274
            # authenticate and create a root to share
 
275
            d = client.dummy_authenticate("open sesame")
 
276
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
277
            d.addCallback(self.save_req, 'root_id')
 
278
 
 
279
            # hook ourselves and create the share
 
280
            d.addCallbacks(lambda r: client.set_share_change_callback(notif),
 
281
                           client.test_fail)
 
282
            d.addCallbacks(
 
283
                lambda _: client.create_share(
 
284
                    self._state.root_id, "usr0", u"name", "View"),
 
285
                client.test_fail)
 
286
 
 
287
        return self.callback_test(auth)
 
288
 
 
289
    def test_notify_creation_to_myself_accepted_yes(self):
 
290
        """Create a share to myself and accept it."""
 
291
 
 
292
        def auth(client):
 
293
            def notif_share(share_notif):
 
294
                #check the DB
 
295
                shares = self.usr0.get_shared_to(accepted=False)
 
296
                share = shares[0]
 
297
                self.assertEquals(share.name, u"acc Y")
 
298
                self.assertEqual(str(share.root_id), self._state.root_id)
 
299
                self.assertEqual(share.access, "View")
 
300
                self.assertEqual(share.accepted, False)
 
301
 
 
302
                # send the answer
 
303
                client.accept_share(share_notif.share_id, "Yes")
 
304
 
 
305
            def notif_answer(share_id, answer):
 
306
                # check the notification
 
307
                self.assertEqual(answer, "Yes")
 
308
 
 
309
                # check the DB
 
310
                share = self.usr0.get_share(share_id)
 
311
                self.assertEqual(str(share.root_id), self._state.root_id)
 
312
                self.assertEqual(share.accepted, True)
 
313
                # so, everything ok!
 
314
                client.test_done()
 
315
 
 
316
            # authenticate and create a root to share
 
317
            d = client.dummy_authenticate("open sesame")
 
318
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
319
            d.addCallback(self.save_req, 'root_id')
 
320
 
 
321
            # hook ourselves to both notifications
 
322
            d.addCallbacks(
 
323
                lambda r: client.set_share_change_callback(notif_share),
 
324
                client.test_fail)
 
325
 
 
326
            d.addCallbacks(
 
327
                lambda r: client.set_share_answer_callback(notif_answer),
 
328
                client.test_fail)
 
329
 
 
330
            # create the share
 
331
            d.addCallbacks(
 
332
                lambda _: client.create_share(
 
333
                    self._state.root_id, self.usr0.username, u"acc Y", "View"),
 
334
                client.test_fail)
 
335
 
 
336
        return self.callback_test(auth)
 
337
 
 
338
    def test_notify_creation_to_myself_accepted_no(self):
 
339
        """Create a share to myself and reject it."""
 
340
 
 
341
        def auth(client):
 
342
            def notif_share(share_notif):
 
343
 
 
344
                #check the DB
 
345
                reg = self.usr0.get_shared_to()[0]
 
346
                self.assertEqual(str(reg.root_id), self._state.root_id)
 
347
                self.assertEqual(reg.access, "View")
 
348
                self.assertEqual(reg.accepted, False)
 
349
                self.assertEqual(reg.status, "Live")
 
350
 
 
351
                # send the answer
 
352
                client.accept_share(share_notif.share_id, "No")
 
353
 
 
354
            def notif_answer(share_id, answer):
 
355
                # check the notification
 
356
                self.assertEqual(answer, "No")
 
357
 
 
358
                # check the DB
 
359
                self.assertRaises(errors.DoesNotExist,
 
360
                                  self.usr0.get_share, share_id)
 
361
 
 
362
                # so, everything ok!
 
363
                client.test_done()
 
364
 
 
365
            # authenticate and create a root to share
 
366
            d = client.dummy_authenticate("open sesame")
 
367
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
368
            d.addCallback(self.save_req, 'root_id')
 
369
 
 
370
            # hook ourselves to both notifications
 
371
            d.addCallbacks(
 
372
                lambda r: client.set_share_change_callback(notif_share),
 
373
                client.test_fail)
 
374
 
 
375
            d.addCallbacks(
 
376
                lambda r: client.set_share_answer_callback(notif_answer),
 
377
                client.test_fail)
 
378
 
 
379
            # create the share
 
380
            d.addCallbacks(
 
381
                lambda _: client.create_share(
 
382
                    self._state.root_id, self.usr0.username, u"acc N", "View"),
 
383
                client.test_fail)
 
384
 
 
385
        return self.callback_test(auth)
 
386
 
 
387
    def test_notify_answer_two_users(self):
 
388
        """Create check answer notifications between two clients."""
 
389
 
 
390
        def login1(client):
 
391
            self._state.client1 = client
 
392
            client.set_share_answer_callback(client1_notif_answer)
 
393
            d = client.dummy_authenticate("open sesame")  # for user #0
 
394
            d.addCallback(new_client)
 
395
            d.addCallback(make_share)
 
396
 
 
397
        def login2(client):
 
398
            self._state.client2 = client
 
399
            client.set_share_change_callback(client2_notif_change)
 
400
            d = client.dummy_authenticate("friend")  # for user #1
 
401
            d.addCallback(done_auth)
 
402
 
 
403
        # setup
 
404
        factory = FactoryHelper(login1)
 
405
        factory2 = FactoryHelper(login2)
 
406
        d1 = defer.Deferred()
 
407
        d2 = defer.Deferred()
 
408
        timeout = reactor.callLater(3, d1.errback, Exception("timeout"))
 
409
 
 
410
        def new_client(_):
 
411
            reactor.connectTCP('localhost', self.port, factory2)
 
412
            return d2
 
413
 
 
414
        def done_auth(result):
 
415
            d2.callback(result)
 
416
 
 
417
        def make_share(_):
 
418
            # create the share
 
419
            client1 = self._state.client1
 
420
            d = client1.get_root()
 
421
            d.addCallback(self.save_req, 'root_id')
 
422
            d.addCallbacks(
 
423
                lambda _: client1.create_share(
 
424
                    self._state.root_id, self.usr1.username, u"acc Y", "View"),
 
425
                client1.test_fail)
 
426
 
 
427
        def client2_notif_change(share_notif):
 
428
            #received change notification for the new share
 
429
            #check the share
 
430
            shares = self.usr1.get_shared_to(accepted=False)
 
431
            share = shares[0]
 
432
            self.assertEquals(share.name, u"acc Y")
 
433
            self.assertEqual(str(share.root_id), self._state.client1.root_id)
 
434
            self.assertEqual(share.access, "View")
 
435
            self.assertEqual(share.accepted, False)
 
436
            # send the answer
 
437
            self._state.client2.accept_share(share_notif.share_id, "Yes")
 
438
 
 
439
        def client1_notif_answer(share_id, answer):
 
440
            # check the notification
 
441
            self.assertEqual(answer, "Yes")
 
442
            #check the share
 
443
            share = self.usr0.get_share(share_id)
 
444
            self.assertEqual(share.accepted, True)
 
445
 
 
446
            # cleanup
 
447
            factory.timeout.cancel()
 
448
            factory2.timeout.cancel()
 
449
            timeout.cancel()
 
450
            d1.callback((share_id, answer))
 
451
            self._state.client1.transport.loseConnection()
 
452
            self._state.client2.transport.loseConnection()
 
453
 
 
454
        reactor.connectTCP('localhost', self.port, factory)
 
455
        return d1
 
456
 
 
457
    def test_notify_creation_bad(self):
 
458
        """Create a share and see that the own user is not notified."""
 
459
 
 
460
        def auth(client):
 
461
            def notif(*args):
 
462
                raise ValueError("This notification shouldn't exist!")
 
463
 
 
464
            # authenticate and create a root to share
 
465
            d = client.dummy_authenticate("open sesame")
 
466
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
467
            d.addCallback(self.save_req, 'root_id')
 
468
 
 
469
            # hook ourselves and create the share
 
470
            d.addCallbacks(lambda r: client.set_share_change_callback(notif),
 
471
                           client.test_fail)
 
472
            d.addCallbacks(
 
473
                lambda _: client.create_share(
 
474
                    self._state.root_id, self.usr1.username, u"name", "View"),
 
475
                client.test_fail)
 
476
 
 
477
            d.addCallbacks(client.test_done, client.test_fail)
 
478
        return self.callback_test(auth)
 
479
 
 
480
    def test_create_got_shareid(self):
 
481
        """Create a share using and check if the share_id is returned. """
 
482
 
 
483
        def auth(client):
 
484
            # authenticate and create a root to share
 
485
            d = client.dummy_authenticate("open sesame")
 
486
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
487
 
 
488
            # create the share
 
489
            def check_share_id(share_id):
 
490
                self.assertFalse(share_id is None, 'Oops!, share_id is None!')
 
491
                return share_id
 
492
 
 
493
            def create_share(r):
 
494
                d = client.create_share(r, self.usr1.username, u"name", "View")
 
495
                d.addCallbacks(check_share_id, client.test_fail)
 
496
                return d
 
497
            d.addCallbacks(lambda r: create_share(r), client.test_fail)
 
498
            d.addCallbacks(client.test_done, client.test_fail)
 
499
 
 
500
        return self.callback_test(auth)
 
501
 
 
502
    def test_accept_dead_share(self):
 
503
        """Try to accept a dead share."""
 
504
        share = self.usr0.root.share(self.usr1.id, u"a dead share")
 
505
        share.delete()
 
506
 
 
507
        def auth(client):
 
508
            # authenticate and create a root to share
 
509
            d = client.dummy_authenticate("open sesame")
 
510
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
511
            # accept the Dead share
 
512
            d.addCallbacks(lambda _: client.accept_share(share.id, "Yes"),
 
513
                           client.test_fail)
 
514
            self.assertFails(d, "DOES_NOT_EXIST")
 
515
            d.addCallbacks(client.test_done)
 
516
 
 
517
        return self.callback_test(auth)
 
518
 
 
519
 
 
520
class TestSharesWithData(TestWithDatabase):
 
521
    """Tests that require simple sharing data setup."""
 
522
 
 
523
    @defer.inlineCallbacks
 
524
    def setUp(self):
 
525
        """Create users, files and shares."""
 
526
        yield super(TestSharesWithData, self).setUp()
 
527
 
 
528
        root1 = self.usr1.root
 
529
        root2 = self.usr2.root
 
530
        filero = root2.make_file(u"file")
 
531
        rwdir = root2.make_subdirectory(u"rwdir")
 
532
        filerw = rwdir.make_file(u"file")
 
533
        subdir = root2.make_subdirectory(u"subdir")
 
534
        subfile = subdir.make_file(u"subfile")
 
535
        subsubdir = subdir.make_subdirectory(u"subsubdir")
 
536
        subsubfile = subsubdir.make_file(u"subsubfile")
 
537
 
 
538
        share = root2.share(0, u"foo", readonly=True)
 
539
        share_other = root2.share(self.usr1.id, u"foo", readonly=True)
 
540
        subshare = subdir.share(0, u"foo2", readonly=True)
 
541
        share_owner = root1.share(0, u"foo3", readonly=True)
 
542
        share_modify = rwdir.share(0, u"foo4")
 
543
        for s in self.usr0.get_shared_to(accepted=False):
 
544
            s.accept()
 
545
        for s in self.usr1.get_shared_to(accepted=False):
 
546
            s.accept()
 
547
 
 
548
        self.share = str(share.id)
 
549
        self.share_modify = str(share_modify.id)
 
550
        self.subshare = str(subshare.id)
 
551
        self.share_other = str(share_other.id)
 
552
        self.share_owner = str(share_owner.id)
 
553
        self.root = root2.id
 
554
        self.filero = str(filero.id)
 
555
        self.subdir = subdir.id
 
556
        self.subfile = subfile.id
 
557
        self.subsubdir = subsubdir.id
 
558
        self.subsubfile = subsubfile.id
 
559
        self.rwdir = rwdir.id
 
560
        self.filerw = str(filerw.id)
 
561
 
 
562
    def test_unlink_mount_point(self):
 
563
        """Test unlinking a dir."""
 
564
 
 
565
        def auth(client):
 
566
            """auth"""
 
567
            d = client.dummy_authenticate("open sesame")
 
568
            d.addCallback(
 
569
                lambda r: client.unlink(self.subshare, str(self.subdir)))
 
570
            self.assertFails(d, "NO_PERMISSION")
 
571
            d.addCallback(client.test_done)
 
572
 
 
573
        return self.callback_test(auth)
 
574
 
 
575
    def test_mkfile_on_share(self):
 
576
        """Create a file on a share."""
 
577
 
 
578
        def auth(client):
 
579
            """auth"""
 
580
            d = client.dummy_authenticate("open sesame")
 
581
            d.addCallback(
 
582
                lambda r: client.make_file(
 
583
                    self.share_modify, self.rwdir, "test_file"))
 
584
            d.addCallbacks(client.test_done, client.test_fail)
 
585
 
 
586
        return self.callback_test(auth)
 
587
 
 
588
    def test_mkfile_on_share_ro(self):
 
589
        """Create a file on a share thats read only."""
 
590
 
 
591
        def auth(client):
 
592
            """auth"""
 
593
            d = client.dummy_authenticate("open sesame")
 
594
            d.addCallback(
 
595
                lambda r: client.make_file(self.share, self.root, "test_file"))
 
596
            d.addCallbacks(client.test_fail, lambda x: client.test_done())
 
597
 
 
598
        return self.callback_test(auth)
 
599
 
 
600
    def test_mkdir_on_share(self):
 
601
        """Create a dir on a share."""
 
602
 
 
603
        def auth(client):
 
604
            """auth"""
 
605
            d = client.dummy_authenticate("open sesame")
 
606
            d.addCallback(
 
607
                lambda r: client.make_dir(
 
608
                    self.share_modify, self.rwdir, "test_dir"))
 
609
            d.addCallbacks(client.test_done, client.test_fail)
 
610
 
 
611
        return self.callback_test(auth)
 
612
 
 
613
    def test_mkdir_on_share_ro(self):
 
614
        """Create a dir on a share thats read only."""
 
615
 
 
616
        def auth(client):
 
617
            """auth"""
 
618
            d = client.dummy_authenticate("open sesame")
 
619
            d.addCallback(
 
620
                lambda r: client.make_dir(self.share, self.root, "test_dir"))
 
621
            d.addCallbacks(client.test_fail, lambda x: client.test_done())
 
622
 
 
623
        return self.callback_test(auth)
 
624
 
 
625
    def test_unlink_on_share(self):
 
626
        """unlink a file on a share."""
 
627
 
 
628
        def auth(client):
 
629
            """auth"""
 
630
            d = client.dummy_authenticate("open sesame")
 
631
            d.addCallback(
 
632
                lambda r: client.unlink(self.share_modify, self.filerw))
 
633
            d.addCallbacks(client.test_done, client.test_fail)
 
634
 
 
635
        return self.callback_test(auth)
 
636
 
 
637
    def test_unlink_on_share_ro(self):
 
638
        """unlink a file on a share thats read only."""
 
639
 
 
640
        def auth(client):
 
641
            """auth"""
 
642
            d = client.dummy_authenticate("open sesame")
 
643
            d.addCallback(
 
644
                lambda r: client.unlink(self.share, self.filero))
 
645
            d.addCallbacks(client.test_fail, lambda x: client.test_done())
 
646
 
 
647
        return self.callback_test(auth)
 
648
 
 
649
    def test_move_on_share(self):
 
650
        """move a file on a share."""
 
651
 
 
652
        def auth(client):
 
653
            """auth"""
 
654
            d = client.dummy_authenticate("open sesame")
 
655
            d.addCallback(
 
656
                lambda r: client.move(
 
657
                    self.share_modify, self.filerw, self.rwdir, "newname"))
 
658
            d.addCallbacks(client.test_done, client.test_fail)
 
659
 
 
660
        return self.callback_test(auth)
 
661
 
 
662
    def test_move_on_share_ro(self):
 
663
        """move a file on a share thats read only."""
 
664
 
 
665
        def auth(client):
 
666
            """auth"""
 
667
            d = client.dummy_authenticate("open sesame")
 
668
            d.addCallback(
 
669
                lambda r: client.move(
 
670
                    self.share, self.filero, self.root, "newname"))
 
671
            d.addCallbacks(client.test_fail, lambda x: client.test_done())
 
672
 
 
673
        return self.callback_test(auth)
 
674
 
 
675
    def test_move_on_share_from_mine(self):
 
676
        """make sure we cant move across roots"""
 
677
 
 
678
        def auth(client):
 
679
            """auth"""
 
680
            d = client.dummy_authenticate("open sesame")
 
681
            d.addCallback(lambda r: client.get_root())
 
682
            d.addCallback(
 
683
                lambda r: client.make_file("", r, "file"))
 
684
            d.addCallback(
 
685
                lambda r: client.move(
 
686
                    self.share_modify, r.new_id, self.root, "newname"))
 
687
            self.assertFails(d, "DOES_NOT_EXIST")
 
688
            d.addCallback(client.test_done)
 
689
 
 
690
        return self.callback_test(auth)
 
691
 
 
692
    def test_get_content_on_share(self):
 
693
        """read a file on a share."""
 
694
        data = ""
 
695
        deflated_data = zlib.compress(data)
 
696
        hash_object = content_hash_factory()
 
697
        hash_object.update(data)
 
698
        hash_value = hash_object.content_hash()
 
699
        crc32_value = crc32(data)
 
700
        size = len(data)
 
701
        deflated_size = len(deflated_data)
 
702
 
 
703
        def auth(client):
 
704
            """auth"""
 
705
            d = client.dummy_authenticate("open sesame")
 
706
            # need to put data to be able to retrieve it!
 
707
            d.addCallback(
 
708
                lambda r: client.put_content(
 
709
                    self.share_modify, self.filerw, NO_CONTENT_HASH,
 
710
                    hash_value, crc32_value, size, deflated_size,
 
711
                    StringIO(deflated_data)))
 
712
            d.addCallback(
 
713
                lambda r: client.get_content(
 
714
                    self.share_modify, self.filerw, EMPTY_HASH))
 
715
            d.addCallbacks(client.test_done, client.test_fail)
 
716
 
 
717
        return self.callback_test(auth)
 
718
 
 
719
    def test_put_content_on_share(self):
 
720
        """write a file on a share."""
 
721
        data = "*" * 100000
 
722
        deflated_data = zlib.compress(data)
 
723
        hash_object = content_hash_factory()
 
724
        hash_object.update(data)
 
725
        hash_value = hash_object.content_hash()
 
726
        crc32_value = crc32(data)
 
727
        size = len(data)
 
728
        deflated_size = len(deflated_data)
 
729
 
 
730
        def auth(client):
 
731
            """auth"""
 
732
            d = client.dummy_authenticate("open sesame")
 
733
            d.addCallback(
 
734
                lambda r: client.put_content(
 
735
                    self.share_modify, self.filerw, NO_CONTENT_HASH,
 
736
                    hash_value, crc32_value, size, deflated_size,
 
737
                    StringIO(deflated_data)))
 
738
            d.addCallbacks(client.test_done, client.test_fail)
 
739
 
 
740
        return self.callback_test(auth)
 
741
 
 
742
    def test_put_content_on_share_ro(self):
 
743
        """Write a file on a share thats read only."""
 
744
        data = "*" * 100000
 
745
        hash_object = content_hash_factory()
 
746
        hash_object.update(data)
 
747
        hash_value = hash_object.content_hash()
 
748
        crc32_value = crc32(data)
 
749
        size = len(data)
 
750
 
 
751
        def auth(client):
 
752
            """auth"""
 
753
            d = client.dummy_authenticate("open sesame")
 
754
            d.addCallback(
 
755
                lambda r: client.put_content(
 
756
                    self.share, self.filero, NO_CONTENT_HASH, hash_value,
 
757
                    crc32_value, size, StringIO(data)))
 
758
            d.addCallbacks(client.test_fail, lambda x: client.test_done())
 
759
 
 
760
        return self.callback_test(auth)
 
761
 
 
762
 
 
763
class TestSharesWithDataLegacy(TestWithDatabase):
 
764
    """Tests that require simple sharing data setup, but legacy."""
 
765
 
 
766
    @defer.inlineCallbacks
 
767
    def setUp(self):
 
768
        """Create users, files and shares."""
 
769
        yield super(TestSharesWithDataLegacy, self).setUp()
 
770
 
 
771
        root1 = self.usr1.root
 
772
        root2 = self.usr2.root
 
773
        file = root2.make_file(u"file")
 
774
        filero = root2.make_file(u"file")
 
775
        rwdir = root2.make_subdirectory(u"rwdir")
 
776
        filerw = rwdir.make_file(u"file")
 
777
        subdir = root2.make_subdirectory(u"subdir")
 
778
        subfile = subdir.make_file(u"subfile")
 
779
        subsubdir = subdir.make_subdirectory(u"subsubdir")
 
780
        subsubfile = subsubdir.make_file(u"subsubfile")
 
781
        store = dbmanager.get_shard_store(self.usr2.shard_id)
 
782
        #set all files with an empty hash
 
783
        store.find(model.StorageObject, model.StorageObject.kind == 'File'
 
784
                   ).set(_content_hash=EMPTY_HASH)
 
785
        store.commit()
 
786
 
 
787
        share = root2.share(0, u"foo", readonly=True)
 
788
        share_other = root2.share(self.usr1.id, u"foo", readonly=True)
 
789
        subshare = subdir.share(0, u"foo2", readonly=True)
 
790
        share_owner = root1.share(0, u"foo3", readonly=True)
 
791
        share_modify = rwdir.share(0, u"foo4")
 
792
        for s in self.usr0.get_shared_to(accepted=False):
 
793
            s.accept()
 
794
        for s in self.usr1.get_shared_to(accepted=False):
 
795
            s.accept()
 
796
 
 
797
        self.share = str(share.id)
 
798
        self.share_modify = str(share_modify.id)
 
799
        self.subshare = str(subshare.id)
 
800
        self.share_other = str(share_other.id)
 
801
        self.share_owner = str(share_owner.id)
 
802
        self.root = root2.id
 
803
        self.file = str(file.id)
 
804
        self.filero = str(filero.id)
 
805
        self.subdir = subdir.id
 
806
        self.subfile = subfile.id
 
807
        self.subsubdir = subsubdir.id
 
808
        self.subsubfile = subsubfile.id
 
809
        self.rwdir = rwdir.id
 
810
        self.filerw = str(filerw.id)
 
811
 
 
812
    def test_get_content_on_share(self):
 
813
        """read a file on a share."""
 
814
 
 
815
        def auth(client):
 
816
            """auth"""
 
817
            d = client.dummy_authenticate("open sesame")
 
818
            # need to put data to be able to retrieve it!
 
819
            d.addCallback(
 
820
                lambda r: client.get_content(
 
821
                    self.share, self.file, EMPTY_HASH))
 
822
            d.addCallbacks(client.test_done, client.test_fail)
 
823
 
 
824
        return self.callback_test(auth)
 
825
 
 
826
    def test_put_content_on_share(self):
 
827
        """write a file on a share."""
 
828
        data = "*" * 100000
 
829
        deflated_data = zlib.compress(data)
 
830
        hash_object = content_hash_factory()
 
831
        hash_object.update(data)
 
832
        hash_value = hash_object.content_hash()
 
833
        crc32_value = crc32(data)
 
834
        size = len(data)
 
835
        deflated_size = len(deflated_data)
 
836
 
 
837
        def auth(client):
 
838
            """auth"""
 
839
            d = client.dummy_authenticate("open sesame")
 
840
            d.addCallback(
 
841
                lambda r: client.put_content(
 
842
                    self.share_modify, self.filerw, EMPTY_HASH, hash_value,
 
843
                    crc32_value, size, deflated_size, StringIO(deflated_data)))
 
844
            d.addCallbacks(client.test_done, client.test_fail)
 
845
 
 
846
        return self.callback_test(auth)
 
847
 
 
848
 
 
849
class TestListShares(TestWithDatabase):
 
850
    """Test list_shares command."""
 
851
 
 
852
    def test_one_share_view(self):
 
853
        """List a created share from_me with View."""
 
854
 
 
855
        def check(resp):
 
856
            self.assertEqual(len(resp.shares), 1)
 
857
            share = resp.shares[0]
 
858
            self.assertEqual(share.direction, "from_me")
 
859
            self.assertEqual(share.other_username, u"usr1")
 
860
            self.assertEqual(share.name, "n1")
 
861
            self.assertEqual(share.access_level, "View")
 
862
            self.assertEqual(share.subtree, uuid.UUID(self._state.root_id))
 
863
 
 
864
        def auth(client):
 
865
            # authenticate and create a root to share
 
866
            d = client.dummy_authenticate("open sesame")
 
867
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
868
            d.addCallback(self.save_req, 'root_id')
 
869
 
 
870
            # create the share
 
871
            d.addCallbacks(
 
872
                lambda r: client.create_share(
 
873
                    r, self.usr1.username, u"n1", "View"),
 
874
                client.test_fail)
 
875
 
 
876
            # list the shares and check
 
877
            d.addCallbacks(lambda _: client.list_shares(), client.test_fail)
 
878
            d.addCallbacks(check, client.test_fail)
 
879
            d.addCallbacks(client.test_done, client.test_fail)
 
880
 
 
881
        return self.callback_test(auth)
 
882
 
 
883
    def test_one_share_modify(self):
 
884
        """List a created share from_me with Modify."""
 
885
 
 
886
        def check(resp):
 
887
            self.assertEqual(len(resp.shares), 1)
 
888
            share = resp.shares[0]
 
889
            self.assertEqual(share.direction, "from_me")
 
890
            self.assertEqual(share.other_username, self.usr1.username)
 
891
            self.assertEqual(share.name, "n1")
 
892
            self.assertEqual(share.access_level, "Modify")
 
893
            self.assertEqual(share.subtree, uuid.UUID(self._state.root_id))
 
894
 
 
895
        def auth(client):
 
896
            # authenticate and create a root to share
 
897
            d = client.dummy_authenticate("open sesame")
 
898
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
899
            d.addCallback(self.save_req, 'root_id')
 
900
 
 
901
            # create the share
 
902
            d.addCallbacks(
 
903
                lambda r: client.create_share(
 
904
                    r, self.usr1.username, u"n1", "Modify"),
 
905
                client.test_fail)
 
906
 
 
907
            # list the shares and check
 
908
            d.addCallbacks(lambda _: client.list_shares(), client.test_fail)
 
909
            d.addCallbacks(check, client.test_fail)
 
910
            d.addCallbacks(client.test_done, client.test_fail)
 
911
 
 
912
        return self.callback_test(auth)
 
913
 
 
914
    def _create_share(self, _, accepted=False):
 
915
        """Creates a share, optionally accepted."""
 
916
        root = self.usr1.root.load()
 
917
        share = root.share(0, u"sharename", readonly=True)
 
918
        if accepted:
 
919
            self.usr0.get_share(share.id).accept()
 
920
        # save the node id to be able to compare it later
 
921
 
 
922
        self.save_req(root.id, 'root_id')
 
923
 
 
924
    def test_shares_to_me_noaccept(self):
 
925
        """List shares where user is recipient, no accepted."""
 
926
 
 
927
        def check(resp):
 
928
            self.assertEqual(len(resp.shares), 1)
 
929
            share = resp.shares[0]
 
930
            self.assertEqual(share.direction, "to_me")
 
931
            self.assertEqual(share.other_username, self.usr1.username)
 
932
            self.assertEqual(share.name, "sharename")
 
933
            self.assertEqual(share.access_level, "View")
 
934
            self.assertEqual(share.accepted, False)
 
935
            self.assertEqual(share.subtree, self._state.root_id)
 
936
 
 
937
        def auth(client):
 
938
            # authenticate and create the share
 
939
            d = client.dummy_authenticate("open sesame")
 
940
            d.addCallback(self._create_share)
 
941
 
 
942
            # list the shares and check
 
943
            d.addCallback(lambda _: client.list_shares())
 
944
            d.addCallback(check)
 
945
            d.addCallbacks(client.test_done, client.test_fail)
 
946
 
 
947
        return self.callback_test(auth)
 
948
 
 
949
    def test_shares_to_me_accepted(self):
 
950
        """List shares where user is recipient, accepted."""
 
951
 
 
952
        def check(resp):
 
953
            self.assertEqual(len(resp.shares), 0)
 
954
 
 
955
        def auth(client):
 
956
            # authenticate and create the share
 
957
            d = client.dummy_authenticate("open sesame")
 
958
            d.addCallback(self._create_share, accepted=True)
 
959
 
 
960
            # list the shares and check
 
961
            d.addCallback(lambda _: client.list_shares())
 
962
            d.addCallback(check)
 
963
            d.addCallbacks(client.test_done, client.test_fail)
 
964
 
 
965
        return self.callback_test(auth)
 
966
 
 
967
    def test_several_shares(self):
 
968
        """List several mixed shares."""
 
969
 
 
970
        def createShare():
 
971
            self.usr1.root.share(self.usr0.id, u"share 3", readonly=True)
 
972
 
 
973
        def check(resp):
 
974
            self.assertEqual(len(resp.shares), 3)
 
975
 
 
976
            share = [s for s in resp.shares if s.name == "share 1"][0]
 
977
            self.assertEqual(share.direction, "from_me")
 
978
            self.assertEqual(share.other_username, self.usr1.username)
 
979
            self.assertEqual(share.access_level, "View")
 
980
 
 
981
            share = [s for s in resp.shares if s.name == "share 2"][0]
 
982
            self.assertEqual(share.direction, "from_me")
 
983
            self.assertEqual(share.other_username, self.usr2.username)
 
984
            self.assertEqual(share.access_level, "Modify")
 
985
 
 
986
            share = [s for s in resp.shares if s.name == "share 3"][0]
 
987
            self.assertEqual(share.direction, "to_me")
 
988
            self.assertEqual(share.other_username, self.usr1.username)
 
989
            self.assertEqual(share.access_level, "View")
 
990
 
 
991
        def auth(client):
 
992
            # authenticate and create a root to share
 
993
            d = client.dummy_authenticate("open sesame")
 
994
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
995
            d.addCallback(self.save_req, 'root_id')
 
996
 
 
997
            # create one share from me with View
 
998
            d.addCallbacks(
 
999
                lambda r: client.create_share(
 
1000
                    self._state.root_id, self.usr1.username,
 
1001
                    u"share 1", "View"),
 
1002
                client.test_fail)
 
1003
 
 
1004
            # create one share from me with Modify
 
1005
            d.addCallbacks(
 
1006
                lambda r: client.create_share(
 
1007
                    self._state.root_id, self.usr2.username,
 
1008
                    u"share 2", "Modify"),
 
1009
                client.test_fail)
 
1010
 
 
1011
            # create the share to me
 
1012
            d.addCallbacks(lambda _: createShare(), client.test_fail)
 
1013
 
 
1014
            # list the shares and check
 
1015
            d.addCallbacks(lambda _: client.list_shares(), client.test_fail)
 
1016
            d.addCallbacks(check, client.test_fail)
 
1017
            d.addCallbacks(client.test_done, client.test_fail)
 
1018
 
 
1019
        return self.callback_test(auth)
 
1020
 
 
1021
    def test_share_offer(self):
 
1022
        """Test a share offer which has no to_user."""
 
1023
 
 
1024
        def createShareOffer():
 
1025
            #test a share offer
 
1026
            self.usr0.root.make_shareoffer(u"me@example.com", u"share Offer",
 
1027
                                           readonly=True)
 
1028
 
 
1029
        def check(resp):
 
1030
            self.assertEqual(len(resp.shares), 1)
 
1031
 
 
1032
            share = [s for s in resp.shares if s.name == "share Offer"][0]
 
1033
            self.assertEqual(share.direction, "from_me")
 
1034
            self.assertEqual(share.other_username, u"")
 
1035
            self.assertEqual(share.access_level, "View")
 
1036
 
 
1037
        def auth(client):
 
1038
            # authenticate and create a root to share
 
1039
            d = client.dummy_authenticate("open sesame")
 
1040
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
1041
            d.addCallback(self.save_req, 'root_id')
 
1042
 
 
1043
            # create the share offer to me
 
1044
            d.addCallbacks(lambda _: createShareOffer(), client.test_fail)
 
1045
 
 
1046
            # list the shares and check
 
1047
            d.addCallbacks(lambda _: client.list_shares(), client.test_fail)
 
1048
            d.addCallbacks(check, client.test_fail)
 
1049
            d.addCallbacks(client.test_done, client.test_fail)
 
1050
 
 
1051
        return self.callback_test(auth)
 
1052
 
 
1053
    def test_dead_share(self):
 
1054
        """Test that Dead shares are not included in the list. """
 
1055
 
 
1056
        def createShare():
 
1057
            share = self.usr1.root.share(self.usr0.id,
 
1058
                                         u"another dead share", readonly=True)
 
1059
            share.delete()
 
1060
 
 
1061
        def check(resp):
 
1062
            self.assertEqual(len(resp.shares), 0, resp.shares)
 
1063
 
 
1064
        def auth(client):
 
1065
            # authenticate and create a root to share
 
1066
            d = client.dummy_authenticate("open sesame")
 
1067
            d.addCallbacks(lambda r: client.get_root(), client.test_fail)
 
1068
            d.addCallback(self.save_req, 'root_id')
 
1069
 
 
1070
            # create the share
 
1071
            d.addCallbacks(lambda _: createShare(), client.test_fail)
 
1072
            # list the shares and check
 
1073
            d.addCallbacks(lambda _: client.list_shares(), client.test_fail)
 
1074
            d.addCallbacks(check, client.test_fail)
 
1075
            d.addCallbacks(client.test_done, client.test_fail)
 
1076
 
 
1077
        return self.callback_test(auth)
 
1078
 
 
1079
    def test_share_in_root_from_me_with_volume_id(self):
 
1080
        """List a share from_me and check that we have the node volume_id."""
 
1081
 
 
1082
        @defer.inlineCallbacks
 
1083
        def auth(client):
 
1084
            # authenticate and create a root to share
 
1085
            yield client.dummy_authenticate("open sesame")
 
1086
            root_id = yield client.get_root()
 
1087
            yield client.create_share(root_id, self.usr1.username,
 
1088
                                      u"n1", "View")
 
1089
            # list the shares and check
 
1090
            resp = yield client.list_shares()
 
1091
            self.assertEqual(len(resp.shares), 1)
 
1092
            share = resp.shares[0]
 
1093
            self.assertEqual(share.direction, "from_me")
 
1094
            self.assertEqual(share.other_username, u"usr1")
 
1095
            self.assertEqual(share.name, "n1")
 
1096
            self.assertEqual(share.access_level, "View")
 
1097
            self.assertEqual(share.subtree, uuid.UUID(root_id))
 
1098
            self.assertEqual(share.subtree_volume_id, None)  # the root
 
1099
 
 
1100
        return self.callback_test(auth, add_default_callbacks=True)
 
1101
 
 
1102
    def test_share_in_udf_from_me_with_volume_id(self):
 
1103
        """List a share from_me and check that we have the node volume_id."""
 
1104
 
 
1105
        @defer.inlineCallbacks
 
1106
        def auth(client):
 
1107
            # authenticate and create a root to share
 
1108
            yield client.dummy_authenticate("open sesame")
 
1109
            yield client.get_root()
 
1110
            udf = yield client.create_udf(u"~/myudf", u"foo")
 
1111
            yield client.create_share(udf.node_id, self.usr1.username,
 
1112
                                      u"n1", "View")
 
1113
            # list the shares and check
 
1114
            resp = yield client.list_shares()
 
1115
            self.assertEqual(len(resp.shares), 1)
 
1116
            share = resp.shares[0]
 
1117
            self.assertEqual(share.direction, "from_me")
 
1118
            self.assertEqual(share.other_username, u"usr1")
 
1119
            self.assertEqual(share.name, "n1")
 
1120
            self.assertEqual(share.access_level, "View")
 
1121
            self.assertEqual(share.subtree, uuid.UUID(udf.node_id))
 
1122
            self.assertEqual(share.subtree_volume_id, uuid.UUID(udf.volume_id))
 
1123
 
 
1124
        return self.callback_test(auth, add_default_callbacks=True)
 
1125
 
 
1126
    def test_share_to_me_without_volume_id(self):
 
1127
        """List a share to_me, check that we don't have the node volume_id."""
 
1128
 
 
1129
        @defer.inlineCallbacks
 
1130
        def auth(client):
 
1131
            # authenticate and create a root to share
 
1132
            yield client.dummy_authenticate("open sesame")
 
1133
            self._create_share(None, accepted=False)
 
1134
            # list the shares and check
 
1135
            resp = yield client.list_shares()
 
1136
            self.assertEqual(len(resp.shares), 1)
 
1137
            share = resp.shares[0]
 
1138
            self.assertEqual(share.direction, "to_me")
 
1139
            self.assertFalse(hasattr(share, 'subtree_volume_id'))
 
1140
 
 
1141
        return self.callback_test(auth, add_default_callbacks=True)
 
1142
 
 
1143
 
 
1144
class TestSharesNotified(TestWithDatabase):
 
1145
    """Test that notifications are sent to share receivers."""
 
1146
 
 
1147
    def test_notify_shared_node(self):
 
1148
        """The notif should be sent to other users if the node is shared."""
 
1149
        def login1(client):
 
1150
            """client1 login"""
 
1151
            self._state.client1 = client
 
1152
            d = client.dummy_authenticate("open sesame")  # for user #0
 
1153
            d.addCallback(lambda _: new_client())
 
1154
            d.addCallback(make_notification)
 
1155
 
 
1156
        def login2(client):
 
1157
            """client2 login"""
 
1158
            self._state.client2 = client
 
1159
            client.set_volume_new_generation_callback(on_notification)
 
1160
            d = client.dummy_authenticate("friend")  # for user #1
 
1161
            d.addCallback(done_auth)
 
1162
 
 
1163
        # setup
 
1164
        factory = FactoryHelper(login1)
 
1165
        factory2 = FactoryHelper(login2)
 
1166
        d1 = defer.Deferred()
 
1167
        d2 = defer.Deferred()
 
1168
        timeout = reactor.callLater(3, d1.errback, Exception("timeout"))
 
1169
 
 
1170
        def new_client():
 
1171
            """add the second client"""
 
1172
            reactor.connectTCP('localhost', self.port, factory2)
 
1173
            return d2
 
1174
 
 
1175
        def on_notification(volume, generation):
 
1176
            """notification arrived, check and cleanup"""
 
1177
            # check
 
1178
            self.assertEqual(volume, self._state.share_id)
 
1179
 
 
1180
            # cleanup
 
1181
            factory.timeout.cancel()
 
1182
            factory2.timeout.cancel()
 
1183
            timeout.cancel()
 
1184
            d1.callback(True)
 
1185
            self._state.client1.transport.loseConnection()
 
1186
            self._state.client2.transport.loseConnection()
 
1187
 
 
1188
        def done_auth(result):
 
1189
            """authentication done for client2, we can start making changes"""
 
1190
            d2.callback(result)
 
1191
 
 
1192
        def mark_share(_):
 
1193
            # mark the share as accepted by hand, so we don't
 
1194
            # have to emulate the whole process just for this test
 
1195
            shares = [s for s in self.usr1.get_shared_to()
 
1196
                      if s.shared_by_id == 0]
 
1197
            share = shares[0]
 
1198
            share.accept()
 
1199
            # also store it in the state for further control
 
1200
            self._state.share_id = share.id
 
1201
 
 
1202
        def make_notification(_):
 
1203
            """create a change that should create a notification"""
 
1204
            # create the share
 
1205
            d = self._state.client1.get_root()
 
1206
            d.addCallback(self.save_req, 'root_id')
 
1207
 
 
1208
            # create the share
 
1209
            d.addCallback(
 
1210
                lambda r: self._state.client1.create_share(
 
1211
                    r, self.usr1.username, u"name", "View"))
 
1212
            d.addCallback(mark_share)
 
1213
 
 
1214
            # create a file in the root
 
1215
            d.addCallback(
 
1216
                lambda _: self._state.client1.make_file(
 
1217
                    request.ROOT, self._state.root_id, "hola"))
 
1218
 
 
1219
        reactor.connectTCP('localhost', self.port, factory)
 
1220
        return d1
 
1221
 
 
1222
    def test_share_node_deleted(self):
 
1223
        '''Remove the node that was shared.'''
 
1224
        def login1(client):
 
1225
            """client1 login"""
 
1226
            self._state.client1 = client
 
1227
            d = client.dummy_authenticate("open sesame")  # for user #0
 
1228
            d.addCallback(new_client)
 
1229
            d.addCallback(make_notification)
 
1230
 
 
1231
        def login2(client):
 
1232
            """client2 login"""
 
1233
            self._state.client2 = client
 
1234
            client.set_share_change_callback(notif1)
 
1235
            d = client.dummy_authenticate("friend")  # for user #1
 
1236
            d.addCallback(done_auth)
 
1237
 
 
1238
        # setup
 
1239
        factory = FactoryHelper(login1)
 
1240
        factory2 = FactoryHelper(login2)
 
1241
        d1 = defer.Deferred()
 
1242
        d2 = defer.Deferred()
 
1243
        timeout = reactor.callLater(3, d1.errback, Exception("timeout"))
 
1244
 
 
1245
        def new_client(_):
 
1246
            """add the second client"""
 
1247
            reactor.connectTCP('localhost', self.port, factory2)
 
1248
            return d2
 
1249
 
 
1250
        def notif1(share_info):
 
1251
            '''First notification, for the created share.'''
 
1252
            self._state.client2.set_share_delete_callback(notif2)
 
1253
 
 
1254
        def notif2(share_id):
 
1255
            '''Second notification, the tested one.'''
 
1256
            # find the real share
 
1257
            self.assertRaises(errors.DoesNotExist,
 
1258
                              self.usr1.get_share, self._state.share_id)
 
1259
 
 
1260
            # cleanup
 
1261
            factory.timeout.cancel()
 
1262
            factory2.timeout.cancel()
 
1263
            timeout.cancel()
 
1264
            d1.callback((share_id))
 
1265
            self._state.client1.transport.loseConnection()
 
1266
            self._state.client2.transport.loseConnection()
 
1267
 
 
1268
        def done_auth(result):
 
1269
            """authentication done for client2, we can start making changes"""
 
1270
            d2.callback(result)
 
1271
 
 
1272
        def mark_share(_):
 
1273
            # mark the share as accepted by hand, so we don't
 
1274
            # have to emulate the whole process just for this test
 
1275
            share = self.usr1.get_shared_to(accepted=False)[0]
 
1276
            share.accept()
 
1277
            # also store it in the state for further control
 
1278
            self._state.share_id = share.id
 
1279
 
 
1280
        def make_notification(_):
 
1281
            """create a change that should create a notification"""
 
1282
            # create the share
 
1283
            client1 = self._state.client1
 
1284
            d = client1.get_root()
 
1285
            d.addCallback(self.save_req, 'root_id')
 
1286
 
 
1287
            # create the dir to share
 
1288
            d.addCallback(lambda r: client1.make_dir(request.ROOT, r, "hi"))
 
1289
            d.addCallback(self.save_req, "req")
 
1290
 
 
1291
            # create the share
 
1292
            d.addCallback(
 
1293
                lambda _: client1.create_share(
 
1294
                    self._state.req.new_id, self.usr1.username,
 
1295
                    u"name", "View"))
 
1296
            d.addCallback(mark_share)
 
1297
 
 
1298
            # remove the shared node
 
1299
            d.addCallback(
 
1300
                lambda _: client1.unlink(request.ROOT, self._state.req.new_id))
 
1301
 
 
1302
        reactor.connectTCP('localhost', self.port, factory)
 
1303
        return d1
 
1304
    test_share_node_deleted.skip = 'LP: #766088'
 
1305
 
 
1306
    def test_share_node_overwritten_with_move(self):
 
1307
        '''Move something else over the node that was shared.'''
 
1308
        def login1(client):
 
1309
            """client1 login"""
 
1310
            self._state.client1 = client
 
1311
            d = client.dummy_authenticate("open sesame")  # for user #0
 
1312
            d.addCallback(new_client)
 
1313
            d.addCallback(make_notification)
 
1314
 
 
1315
        def login2(client):
 
1316
            """client2 login"""
 
1317
            self._state.client2 = client
 
1318
            client.set_share_change_callback(notif1)
 
1319
            d = client.dummy_authenticate("friend")  # for user #1
 
1320
            d.addCallback(done_auth)
 
1321
 
 
1322
        # setup
 
1323
        factory = FactoryHelper(login1)
 
1324
        factory2 = FactoryHelper(login2)
 
1325
        d1 = defer.Deferred()
 
1326
        d2 = defer.Deferred()
 
1327
        timeout = reactor.callLater(3, d1.errback, Exception("timeout"))
 
1328
 
 
1329
        def new_client(_):
 
1330
            """add the second client"""
 
1331
            reactor.connectTCP('localhost', self.port, factory2)
 
1332
            return d2
 
1333
 
 
1334
        def notif1(share_id):
 
1335
            '''First notification, for the created share.'''
 
1336
            self._state.client2.set_share_delete_callback(notif2)
 
1337
 
 
1338
        def notif2(share_id):
 
1339
            '''Second notification, the tested one.'''
 
1340
            # find the real share
 
1341
            self.assertRaises(errors.DoesNotExist,
 
1342
                              self.usr1.get_share, self._state.share_id)
 
1343
 
 
1344
            # cleanup
 
1345
            factory.timeout.cancel()
 
1346
            factory2.timeout.cancel()
 
1347
            timeout.cancel()
 
1348
            d1.callback((share_id))
 
1349
            self._state.client1.transport.loseConnection()
 
1350
            self._state.client2.transport.loseConnection()
 
1351
 
 
1352
        def done_auth(result):
 
1353
            """authentication done for client2, we can start making changes"""
 
1354
            d2.callback(result)
 
1355
 
 
1356
        def mark_share(_):
 
1357
            # mark the share as accepted by hand, so we don't
 
1358
            # have to emulate the whole process just for this test
 
1359
            share = self.usr1.get_shared_to(accepted=False)[0]
 
1360
            share.accept()
 
1361
            # also store it in the state for further control
 
1362
            self._state.share_id = share.id
 
1363
 
 
1364
        def make_notification(_):
 
1365
            """create a change that should create a notification"""
 
1366
            # create the share
 
1367
            client1 = self._state.client1
 
1368
            d = client1.get_root()
 
1369
            d.addCallback(self.save_req, 'root_id')
 
1370
 
 
1371
            # create the dir to share
 
1372
            d.addCallback(lambda r: client1.make_dir(request.ROOT, r, "prnt"))
 
1373
            d.addCallback(self.save_req, 'parent')
 
1374
            d.addCallback(
 
1375
                lambda r: client1.make_dir(request.ROOT, r.new_id, "hi"))
 
1376
            d.addCallback(self.save_req, 'node')
 
1377
 
 
1378
            # create another dir, to be used as source
 
1379
            d.addCallback(
 
1380
                lambda _: client1.make_dir(
 
1381
                    request.ROOT, self._state.root_id, "hi"))
 
1382
            d.addCallback(self.save_req, 'srcdir')
 
1383
 
 
1384
            # create the share
 
1385
            d.addCallback(
 
1386
                lambda _: client1.create_share(
 
1387
                    self._state.node.new_id, self.usr1.username,
 
1388
                    u"name", "View"))
 
1389
            d.addCallback(mark_share)
 
1390
 
 
1391
            # move the source over the shared node
 
1392
            d.addCallback(
 
1393
                lambda _: client1.move(request.ROOT, self._state.srcdir.new_id,
 
1394
                                       self._state.parent.new_id, "hi"))
 
1395
 
 
1396
        reactor.connectTCP('localhost', self.port, factory)
 
1397
        return d1