~didrocks/ubuntuone-client/dont-suffer-zg-crash

« back to all changes in this revision

Viewing changes to tests/eventlog/test_zg_listener.py

  • Committer: Bazaar Package Importer
  • Author(s): Rodney Dawes
  • Date: 2011-02-11 16:18:11 UTC
  • mfrom: (1.1.44 upstream)
  • Revision ID: james.westby@ubuntu.com-20110211161811-lbelxu332e8r2dov
Tags: 1.5.4-0ubuntu1
* New upstream release.
  - Files still get downloaded from unsubscribed folder (LP: #682878)
  - Add subscription capabilities to shares (LP: #708335)
  - Nautilus offers Publish option within other's shares (LP: #712674)
  - Shares dir name may not be unique (LP: #715776)
  - Send a notification when new Volume is available (LP: #702055)
  - Add messaging menu entry for new Volumes (LP: #702075)
  - Aggregate notifications for completed operations (LP: #702128)
  - Send a notification for new Share offers (LP: #702138)
  - Add messaging menu entry for new Share offers (LP: #702144)
* Remove ubuntuone-client-tools as u1sync has been moved out.
* Simplify python package as we don't have multiple python packages now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
#
3
 
# tests.eventlog.test_zg_listener - test logging ZG events
4
 
#
5
 
# Author: Alejandro J. Cura <alecu@canonical.com>
6
 
#
7
 
# Copyright 2010 Canonical Ltd.
8
 
#
9
 
# This program is free software: you can redistribute it and/or modify it
10
 
# under the terms of the GNU General Public License version 3, as published
11
 
# by the Free Software Foundation.
12
 
#
13
 
# This program is distributed in the hope that it will be useful, but
14
 
# WITHOUT ANY WARRANTY; without even the implied warranties of
15
 
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
16
 
# PURPOSE.  See the GNU General Public License for more details.
17
 
#
18
 
# You should have received a copy of the GNU General Public License along
19
 
# with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 
"""Test the event logging from SyncDaemon into Zeitgeist."""
21
 
 
22
 
import logging
23
 
import os
24
 
import shutil
25
 
import unittest
26
 
import uuid
27
 
 
28
 
from twisted.internet import defer
29
 
from zeitgeist.datamodel import Interpretation, Manifestation
30
 
 
31
 
from contrib.testing.testcase import (
32
 
        FakeMain, FakeMainTestCase, BaseTwistedTestCase)
33
 
from ubuntuone.devtools.handlers import MementoHandler
34
 
from ubuntuone.platform.linux import get_udf_path
35
 
from ubuntuone.storageprotocol import client, delta
36
 
from ubuntuone.storageprotocol.request import ROOT
37
 
from ubuntuone.storageprotocol.sharersp import NotifyShareHolder
38
 
from ubuntuone.syncdaemon.action_queue import (
39
 
        RequestQueue, Upload, MakeFile, MakeDir)
40
 
from ubuntuone.eventlog.zg_listener import (
41
 
        zglog, ZeitgeistListener, ACTOR_UBUNTUONE,
42
 
        EVENT_INTERPRETATION_U1_FOLDER_SHARED,
43
 
        EVENT_INTERPRETATION_U1_FOLDER_UNSHARED,
44
 
        EVENT_INTERPRETATION_U1_SHARE_ACCEPTED,
45
 
        EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED,
46
 
        EVENT_INTERPRETATION_U1_CONFLICT_RENAME,
47
 
        EVENT_INTERPRETATION_U1_UDF_CREATED,
48
 
        EVENT_INTERPRETATION_U1_UDF_DELETED,
49
 
        EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED,
50
 
        EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED,
51
 
        MANIFESTATION_U1_CONTACT_DATA_OBJECT, DIRECTORY_MIMETYPE,
52
 
        INTERPRETATION_U1_CONTACT, URI_PROTOCOL_U1,
53
 
        STORAGE_DELETED, STORAGE_NETWORK, STORAGE_LOCAL)
54
 
from ubuntuone.syncdaemon.sync import Sync
55
 
from ubuntuone.syncdaemon.volume_manager import Share, Shared, UDF
56
 
from tests.syncdaemon.test_action_queue import (
57
 
    ConnectedBaseTestCase,
58
 
    FakeSemaphore,
59
 
)
60
 
 
61
 
VOLUME = uuid.UUID('12345678-1234-1234-1234-123456789abc')
62
 
 
63
 
 
64
 
class MockLogger(object):
65
 
    """A mock logger that stores whatever is logged into it."""
66
 
 
67
 
    def __init__(self):
68
 
        """Initialize this instance."""
69
 
        self.events = []
70
 
 
71
 
    def log(self, event):
72
 
        """Log the event."""
73
 
        self.events.append(event)
74
 
 
75
 
def listen_for(event_q, event, callback, count=1, collect=False):
76
 
    """Setup a EQ listener for the specified event."""
77
 
    class Listener(object):
78
 
        """A basic listener to handle the pushed event."""
79
 
 
80
 
        def __init__(self):
81
 
            self.hits = 0
82
 
            self.events = []
83
 
 
84
 
        def _handle_event(self, *args, **kwargs):
85
 
            self.hits += 1
86
 
            if collect:
87
 
                self.events.append((args, kwargs))
88
 
            if self.hits == count:
89
 
                event_q.unsubscribe(self)
90
 
                if collect:
91
 
                    callback(self.events)
92
 
                elif kwargs:
93
 
                    callback((args, kwargs))
94
 
                else:
95
 
                    callback(args)
96
 
 
97
 
    listener = Listener()
98
 
    setattr(listener, 'handle_'+event, listener._handle_event)
99
 
    event_q.subscribe(listener)
100
 
    return listener
101
 
 
102
 
 
103
 
class ZeitgeistListenerTestCase(FakeMainTestCase):
104
 
    """Tests for ZeitgeistListener."""
105
 
 
106
 
    def setUp(self):
107
 
        """Initialize this instance."""
108
 
        super(ZeitgeistListenerTestCase, self).setUp()
109
 
        self.patch(zglog, "ZeitgeistLogger", MockLogger)
110
 
        self.listener = ZeitgeistListener(self.fs, self.vm)
111
 
        self.event_q.subscribe(self.listener)
112
 
 
113
 
    def _listen_for(self, *args, **kwargs):
114
 
        return listen_for(self.main.event_q, *args, **kwargs)
115
 
 
116
 
 
117
 
class ZeitgeistSharesTestCase(ZeitgeistListenerTestCase):
118
 
    """Tests for all Share-related zeitgeist events."""
119
 
 
120
 
    def test_share_created_with_username_is_logged(self):
121
 
        """A ShareCreated event is logged."""
122
 
        fake_username = "fake user"
123
 
        path = os.path.join(self.vm.root.path, 'shared_path')
124
 
        sample_node_id = "node id"
125
 
        self.main.fs.create(path, "")
126
 
        self.main.fs.set_node_id(path, sample_node_id)
127
 
 
128
 
        def fake_create_share(node_id, user, name, access_level, marker, path):
129
 
            """Fake the creation of the share on the server."""
130
 
            self.assertIn(marker, self.vm.marker_share_map)
131
 
            share_id = self.fs.get_by_mdid(marker).share_id
132
 
            self.main.event_q.push('AQ_CREATE_SHARE_OK',
133
 
                                   share_id=share_id,
134
 
                                   marker=marker)
135
 
 
136
 
        self.patch(self.main.action_q, "create_share", fake_create_share)
137
 
        self.vm.create_share(path, fake_username, 'shared_name', 'View')
138
 
 
139
 
        self.assert_folder_shared_is_logged(path, fake_username)
140
 
 
141
 
    def test_share_created_with_email_is_logged(self):
142
 
        """A ShareCreated event is logged."""
143
 
        fake_username = "fakeuser@somewhere.com"
144
 
        path = os.path.join(self.vm.root.path, 'shared_path')
145
 
        sample_node_id = "node id"
146
 
        self.main.fs.create(path, "")
147
 
        self.main.fs.set_node_id(path, sample_node_id)
148
 
 
149
 
        def fake_create_share(node_id, user, name, access_level, marker, path):
150
 
            """Fake the creation of the share on the server."""
151
 
            self.assertIn(marker, self.vm.marker_share_map)
152
 
            self.main.event_q.push('AQ_SHARE_INVITATION_SENT',
153
 
                                   marker=marker)
154
 
 
155
 
        self.patch(self.main.action_q, "create_share", fake_create_share)
156
 
        self.vm.create_share(path, fake_username, 'shared_name', 'View')
157
 
 
158
 
        self.assert_folder_shared_is_logged(path, fake_username)
159
 
 
160
 
    def assert_folder_shared_is_logged(self, path, fake_username):
161
 
        """Assert that the FolderShared event was logged."""
162
 
 
163
 
        self.assertEqual(len(self.listener.zg.events), 1)
164
 
        event = self.listener.zg.events[0]
165
 
 
166
 
        self.assertEqual(event.interpretation,
167
 
                          EVENT_INTERPRETATION_U1_FOLDER_SHARED)
168
 
        self.assertEqual(event.manifestation,
169
 
                          Manifestation.USER_ACTIVITY)
170
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
171
 
 
172
 
        folder = event.subjects[0]
173
 
        self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
174
 
        self.assertEqual(folder.interpretation, Interpretation.FOLDER)
175
 
        self.assertEqual(folder.manifestation,
176
 
                          Manifestation.REMOTE_DATA_OBJECT)
177
 
        self.assertTrue(folder.origin.endswith(path))
178
 
        self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
179
 
        self.assertEqual(folder.storage, STORAGE_NETWORK)
180
 
 
181
 
        other_user = event.subjects[1]
182
 
        self.assertEqual(other_user.uri, "mailto:" + fake_username)
183
 
        self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT)
184
 
        self.assertEqual(other_user.manifestation,
185
 
                          MANIFESTATION_U1_CONTACT_DATA_OBJECT)
186
 
 
187
 
 
188
 
    @defer.inlineCallbacks
189
 
    def test_share_deleted_is_logged(self):
190
 
        """Test VolumeManager.delete_share."""
191
 
        sample_share_id = "share id"
192
 
        sample_node_id = "node id"
193
 
        fake_username = "fake user"
194
 
        path = os.path.join(self.vm.root.path, 'shared_path')
195
 
        self.main.fs.create(path, "")
196
 
        self.main.fs.set_node_id(path, sample_node_id)
197
 
        share = Shared(path=path, volume_id=sample_share_id,
198
 
                       node_id=sample_node_id, other_username=fake_username)
199
 
        self.vm.add_shared(share)
200
 
 
201
 
        def fake_delete_share(share_id):
202
 
            """Fake delete_share."""
203
 
            self.assertEqual(share_id, share.volume_id)
204
 
            self.main.event_q.push('AQ_DELETE_SHARE_OK', share_id=share_id)
205
 
 
206
 
        self.patch(self.main.action_q, 'delete_share', fake_delete_share)
207
 
        d = defer.Deferred()
208
 
        self._listen_for('VM_SHARE_DELETED', d.callback, 1, collect=True)
209
 
        self.vm.delete_share(share.volume_id)
210
 
        yield d
211
 
 
212
 
        self.assertEqual(len(self.listener.zg.events), 1)
213
 
        event = self.listener.zg.events[0]
214
 
 
215
 
        self.assertEqual(event.interpretation,
216
 
                          EVENT_INTERPRETATION_U1_FOLDER_UNSHARED)
217
 
        self.assertEqual(event.manifestation,
218
 
                          Manifestation.USER_ACTIVITY)
219
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
220
 
 
221
 
        folder = event.subjects[0]
222
 
        self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
223
 
        self.assertEqual(folder.interpretation, Interpretation.FOLDER)
224
 
        self.assertEqual(folder.manifestation,
225
 
                          Manifestation.REMOTE_DATA_OBJECT)
226
 
        self.assertTrue(folder.origin.endswith(path))
227
 
        self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
228
 
        self.assertEqual(folder.storage, STORAGE_NETWORK)
229
 
 
230
 
        other_user = event.subjects[1]
231
 
        self.assertEqual(other_user.uri, "mailto:" + fake_username)
232
 
        self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT)
233
 
        self.assertEqual(other_user.manifestation,
234
 
                          MANIFESTATION_U1_CONTACT_DATA_OBJECT)
235
 
 
236
 
    def test_share_accepted_is_logged(self):
237
 
        """Test that an accepted share event is logged."""
238
 
        # initialize the the root
239
 
        self.vm._got_root('root_uuid')
240
 
        fake_username = "fake user"
241
 
        path = os.path.join(self.vm.root.path, 'shared_path')
242
 
        self.main.fs.create(path, "")
243
 
        share_path = os.path.join(self.shares_dir, 'fake_share')
244
 
        share = Share(path=share_path, volume_id='volume_id', node_id="node_id",
245
 
                      other_username=fake_username)
246
 
        self.vm.add_share(share)
247
 
 
248
 
        self.assertEqual(len(self.listener.zg.events), 1)
249
 
        event = self.listener.zg.events[0]
250
 
 
251
 
        self.assertEqual(event.interpretation,
252
 
                          EVENT_INTERPRETATION_U1_SHARE_ACCEPTED)
253
 
        self.assertEqual(event.manifestation,
254
 
                          Manifestation.USER_ACTIVITY)
255
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
256
 
 
257
 
        folder = event.subjects[0]
258
 
        self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
259
 
        self.assertEqual(folder.interpretation, Interpretation.FOLDER)
260
 
        self.assertEqual(folder.manifestation,
261
 
                          Manifestation.REMOTE_DATA_OBJECT)
262
 
        self.assertTrue(folder.origin.endswith(share_path))
263
 
        self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
264
 
        self.assertEqual(folder.storage, STORAGE_NETWORK)
265
 
 
266
 
        other_user = event.subjects[1]
267
 
        self.assertEqual(other_user.uri, "mailto:" + fake_username)
268
 
        self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT)
269
 
        self.assertEqual(other_user.manifestation,
270
 
                          MANIFESTATION_U1_CONTACT_DATA_OBJECT)
271
 
 
272
 
 
273
 
    @defer.inlineCallbacks
274
 
    def test_share_unaccepted_is_logged(self):
275
 
        """Test that an unaccepted share event is logged."""
276
 
        fake_username = "fake user"
277
 
        d = defer.Deferred()
278
 
 
279
 
        share_path = os.path.join(self.main.shares_dir, 'share')
280
 
        holder = NotifyShareHolder.from_params(uuid.uuid4(),
281
 
                                                     uuid.uuid4(),
282
 
                                                     u'fake_share',
283
 
                                                     fake_username,
284
 
                                                     u'visible_name', 'Read')
285
 
 
286
 
        self.main.vm.add_share(Share.from_notify_holder(holder, share_path))
287
 
        self._listen_for('VM_VOLUME_DELETED', d.callback, 1, collect=True)
288
 
        self.main.event_q.push('SV_SHARE_DELETED', share_id=holder.share_id)
289
 
        yield d
290
 
 
291
 
        self.assertEqual(len(self.listener.zg.events), 2)
292
 
        event = self.listener.zg.events[1]
293
 
 
294
 
        self.assertEqual(event.interpretation,
295
 
                          EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED)
296
 
        self.assertEqual(event.manifestation,
297
 
                          Manifestation.USER_ACTIVITY)
298
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
299
 
 
300
 
        folder = event.subjects[0]
301
 
        self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
302
 
        self.assertEqual(folder.interpretation, Interpretation.FOLDER)
303
 
        self.assertEqual(folder.manifestation,
304
 
                          Manifestation.REMOTE_DATA_OBJECT)
305
 
        self.assertTrue(folder.origin.endswith(share_path))
306
 
        self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
307
 
        self.assertEqual(folder.storage, STORAGE_NETWORK)
308
 
 
309
 
        other_user = event.subjects[1]
310
 
        self.assertEqual(other_user.uri, "mailto:" + fake_username)
311
 
        self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT)
312
 
        self.assertEqual(other_user.manifestation,
313
 
                          MANIFESTATION_U1_CONTACT_DATA_OBJECT)
314
 
 
315
 
 
316
 
class ZeitgeistUDFsTestCase(ZeitgeistListenerTestCase):
317
 
    """Tests for all UDFs-related zeitgeist events."""
318
 
 
319
 
    def setUp(self):
320
 
        """Initialize this test instance."""
321
 
        super(ZeitgeistUDFsTestCase, self).setUp()
322
 
        self.home_dir = self.mktemp('ubuntuonehacker')
323
 
        self._old_home = os.environ['HOME']
324
 
        os.environ['HOME'] = self.home_dir
325
 
 
326
 
    def tearDown(self):
327
 
        """Finalize this test instance."""
328
 
        self.rmtree(self.home_dir)
329
 
        os.environ['HOME'] = self._old_home
330
 
        super(ZeitgeistUDFsTestCase, self).tearDown()
331
 
 
332
 
    def _create_udf(self, id, node_id, suggested_path, subscribed=True):
333
 
        """Create an UDF and returns it and the volume."""
334
 
        path = get_udf_path(suggested_path)
335
 
        # make sure suggested_path is unicode
336
 
        if isinstance(suggested_path, str):
337
 
            suggested_path = suggested_path.decode('utf-8')
338
 
        udf = UDF(str(id), str(node_id), suggested_path, path, subscribed)
339
 
        return udf
340
 
 
341
 
    @defer.inlineCallbacks
342
 
    def test_udf_create_is_logged(self):
343
 
        """Test for Folders.create."""
344
 
        path = os.path.join(self.home_dir, u'ñoño'.encode('utf-8'))
345
 
        id = uuid.uuid4()
346
 
        node_id = uuid.uuid4()
347
 
 
348
 
        def create_udf(path, name, marker):
349
 
            """Fake create_udf."""
350
 
            # check that the marker is the full path to the udf
351
 
            expanded_path = os.path.expanduser(path.encode('utf-8'))
352
 
            udf_path = os.path.join(expanded_path, name.encode('utf-8'))
353
 
            if str(marker) != udf_path:
354
 
                d.errback(ValueError("marker != path - "
355
 
                                   "marker: %r path: %r" % (marker, udf_path)))
356
 
            self.main.event_q.push("AQ_CREATE_UDF_OK", **dict(volume_id=id,
357
 
                                                       node_id=node_id,
358
 
                                                       marker=marker))
359
 
 
360
 
        self.patch(self.main.action_q, "create_udf", create_udf)
361
 
 
362
 
        d = defer.Deferred()
363
 
        self._listen_for('VM_UDF_CREATED', d.callback, 1, collect=True)
364
 
        self.vm.create_udf(path)
365
 
        yield d
366
 
 
367
 
        self.assertEqual(len(self.listener.zg.events), 1)
368
 
        event = self.listener.zg.events[0]
369
 
 
370
 
        self.assertEqual(event.interpretation,
371
 
                          EVENT_INTERPRETATION_U1_UDF_CREATED)
372
 
        self.assertEqual(event.manifestation,
373
 
                          Manifestation.USER_ACTIVITY)
374
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
375
 
 
376
 
        folder = event.subjects[0]
377
 
        self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
378
 
        self.assertEqual(folder.interpretation, Interpretation.FOLDER)
379
 
        self.assertEqual(folder.manifestation,
380
 
                          Manifestation.REMOTE_DATA_OBJECT)
381
 
        self.assertTrue(folder.origin.endswith(path))
382
 
        self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
383
 
        self.assertEqual(folder.storage, STORAGE_NETWORK)
384
 
 
385
 
    @defer.inlineCallbacks
386
 
    def test_udf_delete_is_logged(self):
387
 
        """Test for Folders.delete."""
388
 
        id = uuid.uuid4()
389
 
        node_id = uuid.uuid4()
390
 
        path = os.path.join(self.home_dir, u'ñoño'.encode('utf-8'))
391
 
 
392
 
        def create_udf(path, name, marker):
393
 
            """Fake create_udf."""
394
 
            # check that the marker is the full path to the udf
395
 
            expanded_path = os.path.expanduser(path.encode('utf-8'))
396
 
            udf_path = os.path.join(expanded_path, name.encode('utf-8'))
397
 
            if str(marker) != udf_path:
398
 
                d.errback(ValueError("marker != path - "
399
 
                                   "marker: %r path: %r" % (marker, udf_path)))
400
 
            self.main.event_q.push("AQ_CREATE_UDF_OK", **dict(volume_id=id,
401
 
                                                       node_id=node_id,
402
 
                                                       marker=marker))
403
 
 
404
 
        self.patch(self.main.action_q, "create_udf", create_udf)
405
 
 
406
 
        d = defer.Deferred()
407
 
        self._listen_for('VM_UDF_CREATED', d.callback, 1, collect=True)
408
 
        self.vm.create_udf(path)
409
 
        yield d
410
 
 
411
 
        def delete_volume(volume_id, path):
412
 
            """Fake delete_volume."""
413
 
            self.main.event_q.push("AQ_DELETE_VOLUME_OK", volume_id=id)
414
 
 
415
 
        self.patch(self.main.action_q, "delete_volume", delete_volume)
416
 
 
417
 
        self.vm.delete_volume(str(id))
418
 
 
419
 
        self.assertEqual(len(self.listener.zg.events), 1)
420
 
        event = self.listener.zg.events[0]
421
 
 
422
 
        d = defer.Deferred()
423
 
        self._listen_for('VM_VOLUME_DELETED', d.callback, 1, collect=True)
424
 
        yield d
425
 
 
426
 
        self.assertEqual(len(self.listener.zg.events), 2)
427
 
        event = self.listener.zg.events[1]
428
 
 
429
 
        self.assertEqual(event.interpretation,
430
 
                          EVENT_INTERPRETATION_U1_UDF_DELETED)
431
 
        self.assertEqual(event.manifestation,
432
 
                          Manifestation.USER_ACTIVITY)
433
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
434
 
 
435
 
        folder = event.subjects[0]
436
 
        self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
437
 
        self.assertEqual(folder.interpretation, Interpretation.FOLDER)
438
 
        self.assertEqual(folder.manifestation,
439
 
                          Manifestation.DELETED_RESOURCE)
440
 
        self.assertTrue(folder.origin.endswith(path))
441
 
        self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
442
 
        self.assertEqual(folder.storage, STORAGE_DELETED)
443
 
 
444
 
    @defer.inlineCallbacks
445
 
    def test_udf_subscribe_is_logged(self):
446
 
        """Test for Folders.subscribe."""
447
 
        suggested_path = u'~/ñoño'
448
 
        udf = self._create_udf(uuid.uuid4(), 'node_id', suggested_path,
449
 
                               subscribed=False)
450
 
        yield self.main.vm.add_udf(udf)
451
 
        d = defer.Deferred()
452
 
        self._listen_for('VM_UDF_SUBSCRIBED', d.callback, 1, collect=True)
453
 
        self.vm.subscribe_udf(udf.volume_id)
454
 
        yield d
455
 
 
456
 
        self.assertEqual(len(self.listener.zg.events), 2)
457
 
        event = self.listener.zg.events[1]
458
 
 
459
 
        self.assertEqual(event.interpretation,
460
 
                          EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED)
461
 
        self.assertEqual(event.manifestation,
462
 
                          Manifestation.USER_ACTIVITY)
463
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
464
 
 
465
 
        folder = event.subjects[0]
466
 
        self.assertTrue(folder.uri.endswith(udf.path))
467
 
        self.assertEqual(folder.interpretation, Interpretation.FOLDER)
468
 
        self.assertEqual(folder.manifestation,
469
 
                          Manifestation.FILE_DATA_OBJECT)
470
 
        self.assertTrue(folder.origin.startswith(URI_PROTOCOL_U1))
471
 
        self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
472
 
        self.assertEqual(folder.storage, STORAGE_LOCAL)
473
 
 
474
 
    @defer.inlineCallbacks
475
 
    def test_udf_unsubscribe_is_logged(self):
476
 
        """Test for Folders.unsubscribe."""
477
 
        suggested_path = u'~/ñoño'
478
 
        udf = self._create_udf(uuid.uuid4(), 'node_id', suggested_path,
479
 
                               subscribed=True)
480
 
        yield self.main.vm.add_udf(udf)
481
 
        d = defer.Deferred()
482
 
        self._listen_for('VM_UDF_UNSUBSCRIBED', d.callback, 1, collect=True)
483
 
        self.vm.unsubscribe_udf(udf.volume_id)
484
 
        yield d
485
 
 
486
 
        self.assertEqual(len(self.listener.zg.events), 2)
487
 
        event = self.listener.zg.events[1]
488
 
 
489
 
        self.assertEqual(event.interpretation,
490
 
                          EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED)
491
 
        self.assertEqual(event.manifestation,
492
 
                          Manifestation.USER_ACTIVITY)
493
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
494
 
 
495
 
        folder = event.subjects[0]
496
 
        self.assertTrue(folder.uri.endswith(udf.path))
497
 
        self.assertEqual(folder.interpretation, Interpretation.FOLDER)
498
 
        self.assertEqual(folder.manifestation,
499
 
                          Manifestation.DELETED_RESOURCE)
500
 
        self.assertTrue(folder.origin.startswith(URI_PROTOCOL_U1))
501
 
        self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
502
 
        self.assertEqual(folder.storage, STORAGE_DELETED)
503
 
 
504
 
 
505
 
class ZeitgeistRemoteFileSyncTestCase(ConnectedBaseTestCase):
506
 
    """File sync events are logged into Zeitgeist."""
507
 
 
508
 
    def setUp(self):
509
 
        """Initialize this test instance."""
510
 
        ConnectedBaseTestCase.setUp(self)
511
 
        self.rq = request_queue = RequestQueue(action_queue=self.action_queue)
512
 
        self.rq.transfers_semaphore = FakeSemaphore()
513
 
 
514
 
        class MyUpload(Upload):
515
 
            """Just to allow monkeypatching."""
516
 
 
517
 
        self.share_id = ""
518
 
        self.command = MyUpload(request_queue, share_id=self.share_id,
519
 
                                node_id='a_node_id', previous_hash='prev_hash',
520
 
                                hash='yadda', crc32=0, size=0, path='path',
521
 
                                fileobj_factory=lambda: None,
522
 
                                tempfile_factory=lambda: None)
523
 
        self.command.pre_queue_setup() # create the logger
524
 
        self.fsm = self.action_queue.main.fs
525
 
        self.vm = self.action_queue.main.vm
526
 
        self.patch(zglog, "ZeitgeistLogger", MockLogger)
527
 
        self.listener = ZeitgeistListener(self.fsm, self.vm)
528
 
        self.action_queue.event_queue.subscribe(self.listener)
529
 
        self.root_id = "roootid"
530
 
        self.sync = Sync(main=self.main)
531
 
 
532
 
    def tearDown(self):
533
 
        """Finalize this test instance."""
534
 
        ConnectedBaseTestCase.tearDown(self)
535
 
 
536
 
    def test_syncdaemon_creates_file_on_server_is_logged(self):
537
 
        """Files created by SyncDaemon on the server are logged."""
538
 
        filename = "filename.mp3"
539
 
        path = os.path.join(self.vm.root.path, filename)
540
 
        self.fsm.create(path, "")
541
 
        self.fsm.set_node_id(path, "a_node_id")
542
 
 
543
 
        request = client.MakeFile(self.action_queue.client, self.share_id,
544
 
                                  'parent', filename)
545
 
        request.new_id = 'a_node_id'
546
 
        request.new_generation = 13
547
 
 
548
 
        # create a command and trigger it success
549
 
        cmd = MakeFile(self.rq, self.share_id, 'parent', filename,
550
 
                       'marker', path)
551
 
        res = cmd.handle_success(request)
552
 
        assert res is request
553
 
 
554
 
        # create a request and fill it with succesful information
555
 
        request = client.PutContent(self.action_queue.client, self.share_id,
556
 
                                    'node', 'prvhash', 'newhash', 'crc32',
557
 
                                    'size', 'deflated', 'fd')
558
 
        request.new_generation = 13
559
 
 
560
 
        # trigger success in the command
561
 
        self.command.handle_success(request)
562
 
 
563
 
        # check for successful event
564
 
        kwargs = dict(share_id=self.command.share_id, node_id='a_node_id',
565
 
                      hash='yadda', new_generation=13)
566
 
 
567
 
        info = dict(marker='marker', new_id='a_node_id', new_generation=13,
568
 
                    volume_id=self.share_id)
569
 
        events = [
570
 
            ('AQ_FILE_NEW_OK', info),
571
 
            ('AQ_UPLOAD_FINISHED', kwargs),
572
 
        ]
573
 
        self.assertEqual(events, self.command.action_queue.event_queue.events)
574
 
 
575
 
        self.assertEqual(len(self.listener.zg.events), 1)
576
 
        event = self.listener.zg.events[0]
577
 
 
578
 
        self.assertEqual(event.interpretation,
579
 
                          Interpretation.CREATE_EVENT)
580
 
        self.assertEqual(event.manifestation,
581
 
                          Manifestation.SCHEDULED_ACTIVITY)
582
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
583
 
 
584
 
        remote_file = event.subjects[0]
585
 
        self.assertTrue(remote_file.uri.startswith(URI_PROTOCOL_U1))
586
 
        self.assertEqual(remote_file.interpretation, Interpretation.AUDIO)
587
 
        self.assertEqual(remote_file.manifestation,
588
 
                          Manifestation.REMOTE_DATA_OBJECT)
589
 
        self.assertTrue(remote_file.origin.endswith(filename))
590
 
        self.assertEqual(remote_file.mimetype, "audio/mpeg")
591
 
        self.assertEqual(remote_file.storage, STORAGE_NETWORK)
592
 
 
593
 
    def test_syncdaemon_creates_dir_on_server_is_logged(self):
594
 
        """Dirs created by SyncDaemon on the server are logged."""
595
 
        dirname = "dirname"
596
 
        path = os.path.join(self.vm.root.path, dirname)
597
 
        self.fsm.create(path, "")
598
 
        self.fsm.set_node_id(path, "a_node_id")
599
 
 
600
 
        request = client.MakeDir(self.action_queue.client, self.share_id,
601
 
                                  'parent', dirname)
602
 
        request.new_id = 'a_node_id'
603
 
        request.new_generation = 13
604
 
 
605
 
        # create a command and trigger it success
606
 
        cmd = MakeDir(self.rq, self.share_id, 'parent',
607
 
                      dirname, 'marker', path)
608
 
        res = cmd.handle_success(request)
609
 
        assert res is request
610
 
 
611
 
        # check for successful event
612
 
        info = dict(marker='marker', new_id='a_node_id', new_generation=13,
613
 
                    volume_id=self.share_id)
614
 
        events = [('AQ_DIR_NEW_OK', info)]
615
 
        self.assertEqual(events, self.command.action_queue.event_queue.events)
616
 
 
617
 
        self.assertEqual(len(self.listener.zg.events), 1)
618
 
        event = self.listener.zg.events[0]
619
 
 
620
 
        self.assertEqual(event.interpretation,
621
 
                          Interpretation.CREATE_EVENT)
622
 
        self.assertEqual(event.manifestation,
623
 
                          Manifestation.SCHEDULED_ACTIVITY)
624
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
625
 
 
626
 
        remote_file = event.subjects[0]
627
 
        self.assertTrue(remote_file.uri.startswith(URI_PROTOCOL_U1))
628
 
        self.assertEqual(remote_file.interpretation, Interpretation.FOLDER)
629
 
        self.assertEqual(remote_file.manifestation,
630
 
                          Manifestation.REMOTE_DATA_OBJECT)
631
 
        self.assertTrue(remote_file.origin.endswith(dirname))
632
 
        self.assertEqual(remote_file.mimetype, DIRECTORY_MIMETYPE)
633
 
        self.assertEqual(remote_file.storage, STORAGE_NETWORK)
634
 
 
635
 
    def test_syncdaemon_modifies_on_server_is_logged(self):
636
 
        """Files modified by SyncDaemon on the server are logged."""
637
 
        filename = "filename.mp3"
638
 
        path = os.path.join(self.vm.root.path, filename)
639
 
        self.fsm.create(path, "")
640
 
        self.fsm.set_node_id(path, "a_node_id")
641
 
 
642
 
        # create a request and fill it with succesful information
643
 
        request = client.PutContent(self.action_queue.client, self.share_id,
644
 
                                    'node', 'prvhash', 'newhash', 'crc32',
645
 
                                    'size', 'deflated', 'fd')
646
 
        request.new_generation = 13
647
 
 
648
 
        # trigger success in the command
649
 
        self.command.handle_success(request)
650
 
 
651
 
        # check for successful event
652
 
        kwargs = dict(share_id=self.command.share_id, node_id='a_node_id',
653
 
                      hash='yadda', new_generation=13)
654
 
 
655
 
        events = [('AQ_UPLOAD_FINISHED', kwargs)]
656
 
        self.assertEqual(events, self.command.action_queue.event_queue.events)
657
 
 
658
 
        self.assertEqual(len(self.listener.zg.events), 1)
659
 
        event = self.listener.zg.events[0]
660
 
 
661
 
        self.assertEqual(event.interpretation,
662
 
                          Interpretation.MODIFY_EVENT)
663
 
        self.assertEqual(event.manifestation,
664
 
                          Manifestation.SCHEDULED_ACTIVITY)
665
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
666
 
 
667
 
        remote_file = event.subjects[0]
668
 
        self.assertTrue(remote_file.uri.startswith(URI_PROTOCOL_U1))
669
 
        self.assertEqual(remote_file.interpretation, Interpretation.AUDIO)
670
 
        self.assertEqual(remote_file.manifestation,
671
 
                          Manifestation.REMOTE_DATA_OBJECT)
672
 
        self.assertTrue(remote_file.origin.endswith(filename))
673
 
        self.assertEqual(remote_file.mimetype, "audio/mpeg")
674
 
        self.assertEqual(remote_file.storage, STORAGE_NETWORK)
675
 
 
676
 
    @defer.inlineCallbacks
677
 
    def test_syncdaemon_deletes_file_on_server_is_logged(self):
678
 
        """Files deleted by SD on the server are logged."""
679
 
        d = defer.Deferred()
680
 
        listen_for(self.main.event_q, 'AQ_UNLINK_OK', d.callback)
681
 
 
682
 
        path = os.path.join(self.main.vm.root.path, "filename.mp3")
683
 
        self.main.fs.create(path, "")
684
 
        self.main.fs.set_node_id(path, "node_id")
685
 
        self.main.event_q.push("AQ_UNLINK_OK", share_id="",
686
 
                               parent_id="parent_id",
687
 
                               node_id="node_id", new_generation=13)
688
 
        yield d
689
 
 
690
 
        self.assertEqual(len(self.listener.zg.events), 1)
691
 
        event = self.listener.zg.events[0]
692
 
 
693
 
        self.assertEqual(event.interpretation,
694
 
                          Interpretation.DELETE_EVENT)
695
 
        self.assertEqual(event.manifestation,
696
 
                          Manifestation.SCHEDULED_ACTIVITY)
697
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
698
 
 
699
 
        remote_folder = event.subjects[0]
700
 
        self.assertTrue(remote_folder.uri.startswith(URI_PROTOCOL_U1))
701
 
        self.assertEqual(remote_folder.interpretation, Interpretation.AUDIO)
702
 
        self.assertEqual(remote_folder.manifestation,
703
 
                          Manifestation.DELETED_RESOURCE)
704
 
        self.assertTrue(remote_folder.origin.endswith("filename.mp3"))
705
 
        self.assertEqual(remote_folder.mimetype, "audio/mpeg")
706
 
        self.assertEqual(remote_folder.storage, STORAGE_DELETED)
707
 
 
708
 
    @defer.inlineCallbacks
709
 
    def test_syncdaemon_deletes_dir_on_server_is_logged(self):
710
 
        """Files deleted by SD on the server are logged."""
711
 
        d = defer.Deferred()
712
 
        listen_for(self.main.event_q, 'AQ_UNLINK_OK', d.callback)
713
 
 
714
 
        path = os.path.join(self.main.vm.root.path, "folder name")
715
 
        self.main.fs.create(path, "", is_dir=True)
716
 
        self.main.fs.set_node_id(path, "node_id")
717
 
        self.main.event_q.push("AQ_UNLINK_OK", share_id="",
718
 
                               parent_id="parent_id",
719
 
                               node_id="node_id", new_generation=13)
720
 
        yield d
721
 
 
722
 
        self.assertEqual(len(self.listener.zg.events), 1)
723
 
        event = self.listener.zg.events[0]
724
 
 
725
 
        self.assertEqual(event.interpretation,
726
 
                          Interpretation.DELETE_EVENT)
727
 
        self.assertEqual(event.manifestation,
728
 
                          Manifestation.SCHEDULED_ACTIVITY)
729
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
730
 
 
731
 
        remote_folder = event.subjects[0]
732
 
        self.assertTrue(remote_folder.uri.startswith(URI_PROTOCOL_U1))
733
 
        self.assertEqual(remote_folder.interpretation, Interpretation.FOLDER)
734
 
        self.assertEqual(remote_folder.manifestation,
735
 
                          Manifestation.DELETED_RESOURCE)
736
 
        self.assertTrue(remote_folder.origin.endswith("folder name"))
737
 
        self.assertEqual(remote_folder.mimetype, DIRECTORY_MIMETYPE)
738
 
        self.assertEqual(remote_folder.storage, STORAGE_DELETED)
739
 
 
740
 
 
741
 
class ZeitgeistLocalFileSyncTestCase(BaseTwistedTestCase):
742
 
    """Zeitgeist events coming from the server."""
743
 
    timeout = 5
744
 
 
745
 
    def setUp(self):
746
 
        """Initialize this instance."""
747
 
        BaseTwistedTestCase.setUp(self)
748
 
        self.root = self.mktemp('root')
749
 
        self.shares = self.mktemp('shares')
750
 
        self.data = self.mktemp('data')
751
 
        self.partials_dir = self.mktemp('partials_dir')
752
 
        self.handler = MementoHandler()
753
 
        self.handler.setLevel(logging.ERROR)
754
 
        FakeMain._sync_class = Sync
755
 
        self.main = FakeMain(root_dir=self.root, shares_dir=self.shares,
756
 
                             data_dir=self.data,
757
 
                             partials_dir=self.partials_dir)
758
 
        self._logger = logging.getLogger('ubuntuone.SyncDaemon')
759
 
        self._logger.addHandler(self.handler)
760
 
 
761
 
        self.root_id = root_id = "roootid"
762
 
        self.main.vm._got_root(root_id)
763
 
        self.filemp3delta = delta.FileInfoDelta(
764
 
            generation=5, is_live=True, file_type=delta.FILE,
765
 
            parent_id=self.root_id, share_id=ROOT, node_id=uuid.uuid4(),
766
 
            name=u"fileñ.mp3", is_public=False, content_hash="hash",
767
 
            crc32=1, size=10, last_modified=0)
768
 
 
769
 
        self.dirdelta = delta.FileInfoDelta(
770
 
            generation=6, is_live=True, file_type=delta.DIRECTORY,
771
 
            parent_id=root_id, share_id=ROOT, node_id=uuid.uuid4(),
772
 
            name=u"directory_ñ", is_public=False, content_hash="hash",
773
 
            crc32=1, size=10, last_modified=0)
774
 
 
775
 
        self.patch(zglog, "ZeitgeistLogger", MockLogger)
776
 
        self.listener = ZeitgeistListener(self.main.fs, self.main.vm)
777
 
        self.main.event_q.subscribe(self.listener)
778
 
 
779
 
    def tearDown(self):
780
 
        """Clean up this instance."""
781
 
        self._logger.removeHandler(self.handler)
782
 
        self.main.shutdown()
783
 
        FakeMain._sync_class = None
784
 
        shutil.rmtree(self.root)
785
 
        shutil.rmtree(self.shares)
786
 
        shutil.rmtree(self.data)
787
 
        for record in self.handler.records:
788
 
            exc_info = getattr(record, 'exc_info', None)
789
 
            if exc_info is not None:
790
 
                raise exc_info[0], exc_info[1], exc_info[2]
791
 
        BaseTwistedTestCase.tearDown(self)
792
 
 
793
 
    @defer.inlineCallbacks
794
 
    def test_syncdaemon_creates_file_locally_is_logged(self):
795
 
        """Files created locally by SyncDaemon are logged."""
796
 
        d = defer.Deferred()
797
 
        d2 = defer.Deferred()
798
 
        listen_for(self.main.event_q, 'SV_FILE_NEW', d.callback)
799
 
        listen_for(self.main.event_q, 'AQ_DOWNLOAD_FINISHED', d2.callback)
800
 
 
801
 
        deltas = [ self.filemp3delta ]
802
 
        kwargs = dict(volume_id=ROOT, delta_content=deltas, end_generation=11,
803
 
                      full=True, free_bytes=10)
804
 
        self.main.sync.handle_AQ_DELTA_OK(**kwargs)
805
 
 
806
 
        # check that the file is created
807
 
        node = self.main.fs.get_by_node_id(ROOT, self.filemp3delta.node_id)
808
 
        self.assertEqual(node.path, self.filemp3delta.name.encode('utf8'))
809
 
        self.assertEqual(node.is_dir, False)
810
 
        self.assertEqual(node.generation, self.filemp3delta.generation)
811
 
 
812
 
        yield d # wait for SV_FILE_NEW
813
 
 
814
 
        dlargs = dict(
815
 
            share_id=self.filemp3delta.share_id,
816
 
            node_id=self.filemp3delta.node_id,
817
 
            server_hash="server hash")
818
 
        self.main.event_q.push("AQ_DOWNLOAD_FINISHED", **dlargs)
819
 
 
820
 
        yield d2 # wait for AQ_DOWNLOAD_FINISHED
821
 
 
822
 
        self.assertEqual(len(self.listener.zg.events), 1)
823
 
        event = self.listener.zg.events[0]
824
 
 
825
 
        self.assertEqual(event.interpretation,
826
 
                          Interpretation.CREATE_EVENT)
827
 
        self.assertEqual(event.manifestation,
828
 
                          Manifestation.WORLD_ACTIVITY)
829
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
830
 
 
831
 
        local_file = event.subjects[0]
832
 
        self.assertTrue(local_file.uri.endswith(
833
 
                        self.filemp3delta.name.encode('utf8')))
834
 
        self.assertEqual(local_file.interpretation, Interpretation.AUDIO)
835
 
        self.assertEqual(local_file.manifestation,
836
 
                          Manifestation.FILE_DATA_OBJECT)
837
 
        self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1))
838
 
        self.assertEqual(local_file.mimetype, "audio/mpeg")
839
 
        self.assertEqual(local_file.storage, STORAGE_LOCAL)
840
 
 
841
 
    @defer.inlineCallbacks
842
 
    def test_syncdaemon_creates_dir_locally_is_logged(self):
843
 
        """Dirs created locally by SyncDaemon are logged."""
844
 
        d = defer.Deferred()
845
 
        listen_for(self.main.event_q, 'SV_DIR_NEW', d.callback)
846
 
 
847
 
        deltas = [ self.dirdelta ]
848
 
        kwargs = dict(volume_id=ROOT, delta_content=deltas, end_generation=11,
849
 
                      full=True, free_bytes=10)
850
 
        self.main.sync.handle_AQ_DELTA_OK(**kwargs)
851
 
 
852
 
        # check that the dir is created
853
 
        node = self.main.fs.get_by_node_id(ROOT, self.dirdelta.node_id)
854
 
        self.assertEqual(node.path, self.dirdelta.name.encode('utf8'))
855
 
        self.assertEqual(node.is_dir, True)
856
 
        self.assertEqual(node.generation, self.dirdelta.generation)
857
 
 
858
 
        yield d # wait for SV_DIR_NEW
859
 
 
860
 
        self.assertEqual(len(self.listener.zg.events), 1)
861
 
        event = self.listener.zg.events[0]
862
 
 
863
 
        self.assertEqual(event.interpretation,
864
 
                          Interpretation.CREATE_EVENT)
865
 
        self.assertEqual(event.manifestation,
866
 
                          Manifestation.WORLD_ACTIVITY)
867
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
868
 
 
869
 
        local_file = event.subjects[0]
870
 
        self.assertTrue(local_file.uri.endswith(
871
 
                        self.dirdelta.name.encode('utf8')))
872
 
        self.assertEqual(local_file.interpretation, Interpretation.FOLDER)
873
 
        self.assertEqual(local_file.manifestation,
874
 
                          Manifestation.FILE_DATA_OBJECT)
875
 
        self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1))
876
 
        self.assertEqual(local_file.mimetype, DIRECTORY_MIMETYPE)
877
 
        self.assertEqual(local_file.storage, STORAGE_LOCAL)
878
 
 
879
 
    @defer.inlineCallbacks
880
 
    def test_syncdaemon_modifies_locally_is_logged(self):
881
 
        """Files modified locally by SyncDaemon are logged."""
882
 
        d = defer.Deferred()
883
 
        d2 = defer.Deferred()
884
 
        listen_for(self.main.event_q, 'SV_FILE_NEW', d.callback)
885
 
        listen_for(self.main.event_q, 'AQ_DOWNLOAD_FINISHED', d2.callback)
886
 
 
887
 
        deltas = [ self.filemp3delta ]
888
 
        kwargs = dict(volume_id=ROOT, delta_content=deltas, end_generation=11,
889
 
                      full=True, free_bytes=10)
890
 
        self.main.sync.handle_AQ_DELTA_OK(**kwargs)
891
 
 
892
 
        # check that the file is modified
893
 
        node = self.main.fs.get_by_node_id(ROOT, self.filemp3delta.node_id)
894
 
        self.assertEqual(node.path, self.filemp3delta.name.encode('utf8'))
895
 
        self.assertEqual(node.is_dir, False)
896
 
        self.assertEqual(node.generation, self.filemp3delta.generation)
897
 
 
898
 
        yield d # wait for SV_FILE_NEW
899
 
 
900
 
        # remove from the recent list
901
 
        local_file_id = (self.filemp3delta.share_id, self.filemp3delta.node_id)
902
 
        self.listener.newly_created_local_files.remove(local_file_id)
903
 
 
904
 
        dlargs = dict(
905
 
            share_id=self.filemp3delta.share_id,
906
 
            node_id=self.filemp3delta.node_id,
907
 
            server_hash="server hash")
908
 
        self.main.event_q.push("AQ_DOWNLOAD_FINISHED", **dlargs)
909
 
 
910
 
        yield d2 # wait for AQ_DOWNLOAD_FINISHED
911
 
 
912
 
        self.assertEqual(len(self.listener.zg.events), 1)
913
 
        event = self.listener.zg.events[0]
914
 
 
915
 
        self.assertEqual(event.interpretation,
916
 
                          Interpretation.MODIFY_EVENT)
917
 
        self.assertEqual(event.manifestation,
918
 
                          Manifestation.WORLD_ACTIVITY)
919
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
920
 
 
921
 
        local_file = event.subjects[0]
922
 
        self.assertTrue(local_file.uri.endswith(
923
 
                        self.filemp3delta.name.encode('utf8')))
924
 
        self.assertEqual(local_file.interpretation, Interpretation.AUDIO)
925
 
        self.assertEqual(local_file.manifestation,
926
 
                          Manifestation.FILE_DATA_OBJECT)
927
 
        self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1))
928
 
        self.assertEqual(local_file.mimetype, "audio/mpeg")
929
 
        self.assertEqual(local_file.storage, STORAGE_LOCAL)
930
 
 
931
 
    @defer.inlineCallbacks
932
 
    def test_syncdaemon_deletes_file_locally_is_logged(self):
933
 
        """Files deleted locally by SyncDaemon are logged."""
934
 
        d = defer.Deferred()
935
 
        listen_for(self.main.event_q, 'SV_FILE_DELETED', d.callback)
936
 
 
937
 
        filename = self.filemp3delta.name.encode("utf-8")
938
 
        path = os.path.join(self.main.vm.root.path, filename)
939
 
        self.main.fs.create(path, "")
940
 
        self.main.fs.set_node_id(path, "node_id")
941
 
        self.main.event_q.push("SV_FILE_DELETED", volume_id="",
942
 
                               node_id="node_id", is_dir=False)
943
 
 
944
 
        yield d
945
 
 
946
 
        self.assertEqual(len(self.listener.zg.events), 1)
947
 
        event = self.listener.zg.events[0]
948
 
 
949
 
        self.assertEqual(event.interpretation,
950
 
                          Interpretation.DELETE_EVENT)
951
 
        self.assertEqual(event.manifestation,
952
 
                          Manifestation.WORLD_ACTIVITY)
953
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
954
 
 
955
 
        local_file = event.subjects[0]
956
 
        self.assertTrue(local_file.uri.endswith(
957
 
                        self.filemp3delta.name.encode('utf8')))
958
 
        self.assertEqual(local_file.interpretation, Interpretation.AUDIO)
959
 
        self.assertEqual(local_file.manifestation,
960
 
                          Manifestation.DELETED_RESOURCE)
961
 
        self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1))
962
 
        self.assertEqual(local_file.mimetype, "audio/mpeg")
963
 
        self.assertEqual(local_file.storage, STORAGE_DELETED)
964
 
 
965
 
    @defer.inlineCallbacks
966
 
    def test_syncdaemon_deletes_dir_locally_is_logged(self):
967
 
        """Dirs deleted locally by SyncDaemon are logged."""
968
 
        d = defer.Deferred()
969
 
        listen_for(self.main.event_q, 'SV_FILE_DELETED', d.callback)
970
 
 
971
 
        path = os.path.join(self.main.vm.root.path, "folder name")
972
 
        self.main.fs.create(path, "", is_dir=True)
973
 
        self.main.fs.set_node_id(path, "node_id")
974
 
        self.main.event_q.push("SV_FILE_DELETED", volume_id="",
975
 
                               node_id="node_id", is_dir=True)
976
 
 
977
 
        yield d
978
 
 
979
 
        self.assertEqual(len(self.listener.zg.events), 1)
980
 
        event = self.listener.zg.events[0]
981
 
 
982
 
        self.assertEqual(event.interpretation,
983
 
                          Interpretation.DELETE_EVENT)
984
 
        self.assertEqual(event.manifestation,
985
 
                          Manifestation.WORLD_ACTIVITY)
986
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
987
 
 
988
 
        local_folder = event.subjects[0]
989
 
        self.assertTrue(local_folder.uri.endswith("folder name"))
990
 
        self.assertEqual(local_folder.interpretation, Interpretation.FOLDER)
991
 
        self.assertEqual(local_folder.manifestation,
992
 
                          Manifestation.DELETED_RESOURCE)
993
 
        self.assertTrue(local_folder.origin.startswith(URI_PROTOCOL_U1))
994
 
        self.assertEqual(local_folder.mimetype, DIRECTORY_MIMETYPE)
995
 
        self.assertEqual(local_folder.storage, STORAGE_DELETED)
996
 
 
997
 
    @defer.inlineCallbacks
998
 
    def test_file_sync_conflict_is_logged(self):
999
 
        """Files renamed because of conflict are logged."""
1000
 
        d = defer.Deferred()
1001
 
        listen_for(self.main.event_q, 'FSM_FILE_CONFLICT', d.callback)
1002
 
 
1003
 
        testfile = os.path.join(self.main.vm.root.path, 'sample.mp3')
1004
 
        mdid = self.main.fs.create(testfile, "")
1005
 
        self.main.fs.set_node_id(testfile, "uuid")
1006
 
        with open(testfile, "w") as fh:
1007
 
            fh.write("this is music!")
1008
 
 
1009
 
        self.main.fs.move_to_conflict(mdid)
1010
 
 
1011
 
        yield d
1012
 
 
1013
 
        self.assertEqual(len(self.listener.zg.events), 1)
1014
 
        event = self.listener.zg.events[0]
1015
 
 
1016
 
        self.assertEqual(event.interpretation,
1017
 
                          EVENT_INTERPRETATION_U1_CONFLICT_RENAME)
1018
 
        self.assertEqual(event.manifestation,
1019
 
                          Manifestation.WORLD_ACTIVITY)
1020
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1021
 
 
1022
 
        local_file = event.subjects[0]
1023
 
        new_name = testfile + self.main.fs.CONFLICT_SUFFIX
1024
 
        self.assertTrue(local_file.uri.endswith(new_name))
1025
 
        self.assertEqual(local_file.interpretation, Interpretation.AUDIO)
1026
 
        self.assertEqual(local_file.manifestation,
1027
 
                          Manifestation.FILE_DATA_OBJECT)
1028
 
        self.assertTrue(local_file.origin.endswith(testfile))
1029
 
        self.assertEqual(local_file.mimetype, "audio/mpeg")
1030
 
        self.assertEqual(local_file.storage, STORAGE_LOCAL)
1031
 
 
1032
 
    @defer.inlineCallbacks
1033
 
    def test_dir_sync_conflict_is_logged(self):
1034
 
        """Dirs renamed because of conflict are logged."""
1035
 
        d = defer.Deferred()
1036
 
        listen_for(self.main.event_q, 'FSM_DIR_CONFLICT', d.callback)
1037
 
 
1038
 
        testdir = os.path.join(self.main.vm.root.path, 'sampledir')
1039
 
        mdid = self.main.fs.create(testdir, "", is_dir=True)
1040
 
        self.main.fs.set_node_id(testdir, "uuid")
1041
 
        os.mkdir(testdir)
1042
 
 
1043
 
        self.main.fs.move_to_conflict(mdid)
1044
 
 
1045
 
        yield d
1046
 
 
1047
 
        self.assertEqual(len(self.listener.zg.events), 1)
1048
 
        event = self.listener.zg.events[0]
1049
 
 
1050
 
        self.assertEqual(event.interpretation,
1051
 
                          EVENT_INTERPRETATION_U1_CONFLICT_RENAME)
1052
 
        self.assertEqual(event.manifestation,
1053
 
                          Manifestation.WORLD_ACTIVITY)
1054
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1055
 
 
1056
 
        local_file = event.subjects[0]
1057
 
        new_name = testdir + self.main.fs.CONFLICT_SUFFIX
1058
 
        self.assertTrue(local_file.uri.endswith(new_name))
1059
 
        self.assertEqual(local_file.interpretation, Interpretation.FOLDER)
1060
 
        self.assertEqual(local_file.manifestation,
1061
 
                          Manifestation.FILE_DATA_OBJECT)
1062
 
        self.assertTrue(local_file.origin.endswith(testdir))
1063
 
        self.assertEqual(local_file.mimetype, DIRECTORY_MIMETYPE)
1064
 
        self.assertEqual(local_file.storage, STORAGE_LOCAL)
1065
 
 
1066
 
class ZeitgeistPublicFilesTestCase(ZeitgeistListenerTestCase):
1067
 
    """Public files events are logged into Zeitgeist."""
1068
 
 
1069
 
    @defer.inlineCallbacks
1070
 
    def test_publish_url_is_logged(self):
1071
 
        """Publishing a file with a url is logged."""
1072
 
        share_id = "share"
1073
 
        node_id = "node_id"
1074
 
        is_public = True
1075
 
        public_url = 'http://example.com/foo.mp3'
1076
 
 
1077
 
        share_path = os.path.join(self.shares_dir, 'share')
1078
 
        self.main.vm.add_share(Share(path=share_path, volume_id='share',
1079
 
                               other_username='other username'))
1080
 
        path = os.path.join(share_path, "foo.mp3")
1081
 
        self.main.fs.create(path, str(share_id))
1082
 
        self.main.fs.set_node_id(path, str(node_id))
1083
 
 
1084
 
        d = defer.Deferred()
1085
 
        self._listen_for('AQ_CHANGE_PUBLIC_ACCESS_OK', d.callback)
1086
 
        self.main.event_q.push('AQ_CHANGE_PUBLIC_ACCESS_OK',
1087
 
                               share_id=share_id, node_id=node_id,
1088
 
                               is_public=is_public, public_url=public_url)
1089
 
        yield d
1090
 
 
1091
 
        self.assertEqual(len(self.listener.zg.events), 2)
1092
 
        event = self.listener.zg.events[1]
1093
 
 
1094
 
        self.assertEqual(event.interpretation,
1095
 
                          Interpretation.CREATE_EVENT)
1096
 
        self.assertEqual(event.manifestation,
1097
 
                          Manifestation.USER_ACTIVITY)
1098
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1099
 
 
1100
 
        public_file = event.subjects[0]
1101
 
        self.assertEqual(public_file.uri, public_url)
1102
 
        self.assertEqual(public_file.interpretation, Interpretation.AUDIO)
1103
 
        self.assertEqual(public_file.manifestation,
1104
 
                          Manifestation.REMOTE_DATA_OBJECT)
1105
 
        self.assertTrue(public_file.origin.endswith(node_id))
1106
 
        self.assertEqual(public_file.mimetype, "audio/mpeg")
1107
 
        self.assertEqual(public_file.storage, STORAGE_NETWORK)
1108
 
 
1109
 
    @defer.inlineCallbacks
1110
 
    def test_unpublish_url_is_logged(self):
1111
 
        """Unpublishing a file with a url is logged."""
1112
 
        share_id = "share"
1113
 
        node_id = "node_id"
1114
 
        is_public = False
1115
 
        public_url = 'http://example.com/foo.mp3'
1116
 
 
1117
 
        share_path = os.path.join(self.shares_dir, 'share')
1118
 
        self.main.vm.add_share(Share(path=share_path, volume_id='share',
1119
 
                               other_username='other username'))
1120
 
        path = os.path.join(share_path, "foo.mp3")
1121
 
        self.main.fs.create(path, str(share_id))
1122
 
        self.main.fs.set_node_id(path, str(node_id))
1123
 
 
1124
 
        d = defer.Deferred()
1125
 
        self._listen_for('AQ_CHANGE_PUBLIC_ACCESS_OK', d.callback)
1126
 
        self.main.event_q.push('AQ_CHANGE_PUBLIC_ACCESS_OK',
1127
 
                               share_id=share_id, node_id=node_id,
1128
 
                               is_public=is_public, public_url=public_url)
1129
 
        yield d
1130
 
 
1131
 
        self.assertEqual(len(self.listener.zg.events), 2)
1132
 
        event = self.listener.zg.events[1]
1133
 
 
1134
 
        self.assertEqual(event.interpretation,
1135
 
                          Interpretation.DELETE_EVENT)
1136
 
        self.assertEqual(event.manifestation,
1137
 
                          Manifestation.USER_ACTIVITY)
1138
 
        self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1139
 
 
1140
 
        public_file = event.subjects[0]
1141
 
        self.assertEqual(public_file.uri, public_url)
1142
 
        self.assertEqual(public_file.interpretation, Interpretation.AUDIO)
1143
 
        self.assertEqual(public_file.manifestation,
1144
 
                          Manifestation.DELETED_RESOURCE)
1145
 
        self.assertTrue(public_file.origin.endswith(node_id))
1146
 
        self.assertEqual(public_file.mimetype, "audio/mpeg")
1147
 
        self.assertEqual(public_file.storage, STORAGE_DELETED)
1148
 
 
1149
 
 
1150
 
def test_suite():
1151
 
    """Collect these tests only on linux."""
1152
 
    import sys
1153
 
    if sys.platform == 'linux2':
1154
 
        tests = unittest.TestLoader().loadTestsFromName(__name__)
1155
 
    else:
1156
 
        tests = []
1157
 
    return tests