Merge lp:~dobey/ubuntuone-client/rm-zeitgeist into lp:ubuntuone-client

Proposed by dobey
Status: Merged
Approved by: dobey
Approved revision: 1384
Merged at revision: 1384
Proposed branch: lp:~dobey/ubuntuone-client/rm-zeitgeist
Merge into: lp:ubuntuone-client
Diff against target: 2477 lines (+0/-2349)
15 files modified
contrib/testing/testcase.py (+0/-1)
tests/platform/event_logging/__init__.py (+0/-27)
tests/platform/event_logging/test_linux.py (+0/-92)
tests/platform/event_logging/test_windows.py (+0/-43)
tests/platform/linux/eventlog/__init__.py (+0/-27)
tests/platform/linux/eventlog/test_zg_listener.py (+0/-1216)
tests/platform/linux/eventlog/test_zglog.py (+0/-174)
tests/syncdaemon/test_main.py (+0/-14)
tests/syncdaemon/test_status_listener.py (+0/-6)
ubuntuone/eventlog/__init__.py (+0/-29)
ubuntuone/eventlog/zg_listener.py (+0/-556)
ubuntuone/eventlog/zglog.py (+0/-61)
ubuntuone/platform/event_logging/__init__.py (+0/-39)
ubuntuone/platform/event_logging/linux.py (+0/-51)
ubuntuone/syncdaemon/main.py (+0/-13)
To merge this branch: bzr merge lp:~dobey/ubuntuone-client/rm-zeitgeist
Reviewer Review Type Date Requested Status
Mike McCracken (community) Approve
Alejandro J. Cura (community) Approve
Review via email: mp+146454@code.launchpad.net

Commit message

Remove usage of zg to reduce complexity, as we aren't using the feature.

To post a comment you must log in.
Revision history for this message
Alejandro J. Cura (alecu) wrote :

The code removal looks good. +1
We never ended up giving this any real usage, since we found better ways to do the status reporting. So I'm happy that all of this is finally gone.

review: Approve
Revision history for this message
Mike McCracken (mikemc) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'contrib/testing/testcase.py'
--- contrib/testing/testcase.py 2013-01-22 20:03:12 +0000
+++ contrib/testing/testcase.py 2013-02-04 16:10:53 +0000
@@ -293,7 +293,6 @@
293 self.lr = local_rescan.LocalRescan(self.vm, self.fs,293 self.lr = local_rescan.LocalRescan(self.vm, self.fs,
294 self.event_q, self.action_q)294 self.event_q, self.action_q)
295295
296 self.eventlog_listener = None
297 self.status_listener = FakeStatusListener()296 self.status_listener = FakeStatusListener()
298297
299 def _connect_aq(self, _):298 def _connect_aq(self, _):
300299
=== removed directory 'tests/platform/event_logging'
=== removed file 'tests/platform/event_logging/__init__.py'
--- tests/platform/event_logging/__init__.py 2012-05-02 22:09:13 +0000
+++ tests/platform/event_logging/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,27 +0,0 @@
1# Copyright 2012 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14#
15# In addition, as a special exception, the copyright holders give
16# permission to link the code of portions of this program with the
17# OpenSSL library under certain conditions as described in each
18# individual source file, and distribute linked combinations
19# including the two.
20# You must obey the GNU General Public License in all respects
21# for all of the code used other than OpenSSL. If you modify
22# file(s) with this exception, you may extend this exception to your
23# version of the file(s), but you are not obligated to do so. If you
24# do not wish to do so, delete this exception statement from your
25# version. If you delete this exception statement from all source
26# files in the program, then also delete it here.
27"""Platform/event_logging test code."""
280
=== removed file 'tests/platform/event_logging/test_linux.py'
--- tests/platform/event_logging/test_linux.py 2012-05-02 22:09:13 +0000
+++ tests/platform/event_logging/test_linux.py 1970-01-01 00:00:00 +0000
@@ -1,92 +0,0 @@
1# tests.platform.event_logging.test_linux
2#
3# Author: Alejandro J. Cura <alecu@canonical.com>
4#
5# Copyright 2010-2012 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19# In addition, as a special exception, the copyright holders give
20# permission to link the code of portions of this program with the
21# OpenSSL library under certain conditions as described in each
22# individual source file, and distribute linked combinations
23# including the two.
24# You must obey the GNU General Public License in all respects
25# for all of the code used other than OpenSSL. If you modify
26# file(s) with this exception, you may extend this exception to your
27# version of the file(s), but you are not obligated to do so. If you
28# do not wish to do so, delete this exception statement from your
29# version. If you delete this exception statement from all source
30# files in the program, then also delete it here.
31"""Test the event logging on linux."""
32
33import sys
34
35from twisted.trial.unittest import TestCase
36
37import ubuntuone.platform.event_logging.linux as event_logging
38
39
40class ZeitgeistDetectionTestCase(TestCase):
41 """Test the is_zeitgeist_installed function."""
42
43 def patch_module(self, module_name, fake_module):
44 """Monkey patch a module for the duration of the test."""
45 UNDEFINED = object()
46 real_module = sys.modules.get(module_name, UNDEFINED)
47
48 def restore():
49 """Restore the real_module."""
50 if real_module is UNDEFINED:
51 del(sys.modules[module_name])
52 else:
53 sys.modules[module_name] = real_module
54
55 self.addCleanup(restore)
56 sys.modules[module_name] = fake_module
57
58 def test_zg_installed_returns_true(self):
59 """When zg is installed, it returns true."""
60 self.patch_module("zeitgeist", object())
61 self.patch_module("zeitgeist.mimetypes", object())
62 result = event_logging.is_zeitgeist_installed()
63 self.assertEqual(result, True)
64
65 def test_zg_not_installed_returns_false(self):
66 """When zg is not installed, it returns false."""
67 self.patch_module("zeitgeist", None)
68 result = event_logging.is_zeitgeist_installed()
69 self.assertEqual(result, False)
70
71 def test_old_zg_installed_returns_false(self):
72 """When an old zg is installed, it returns false."""
73 self.patch_module("zeitgeist", object())
74 self.patch_module("zeitgeist.mimetypes", None)
75 result = event_logging.is_zeitgeist_installed()
76 self.assertEqual(result, False)
77
78
79class GetListenerTestCase(TestCase):
80 """The zg listener is created."""
81
82 def test_zeitgeist_installed_returns_listener(self):
83 """get_listener returns a listener if ZG installed."""
84 self.patch(event_logging, "is_zeitgeist_installed", lambda: True)
85 listener = event_logging.get_listener(None, None)
86 self.assertNotEqual(listener, None)
87
88 def test_zeitgeist_not_installed_returns_none(self):
89 """get_listener returns None if ZG not installed."""
90 self.patch(event_logging, "is_zeitgeist_installed", lambda: False)
91 listener = event_logging.get_listener(None, None)
92 self.assertEqual(listener, None)
930
=== removed file 'tests/platform/event_logging/test_windows.py'
--- tests/platform/event_logging/test_windows.py 2012-05-02 22:09:13 +0000
+++ tests/platform/event_logging/test_windows.py 1970-01-01 00:00:00 +0000
@@ -1,43 +0,0 @@
1# tests.platform.windows.test_event_logging
2#
3# Author: Alejandro J. Cura <alecu@canonical.com>
4#
5# Copyright 2010-2012 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19# In addition, as a special exception, the copyright holders give
20# permission to link the code of portions of this program with the
21# OpenSSL library under certain conditions as described in each
22# individual source file, and distribute linked combinations
23# including the two.
24# You must obey the GNU General Public License in all respects
25# for all of the code used other than OpenSSL. If you modify
26# file(s) with this exception, you may extend this exception to your
27# version of the file(s), but you are not obligated to do so. If you
28# do not wish to do so, delete this exception statement from your
29# version. If you delete this exception statement from all source
30# files in the program, then also delete it here.
31"""Test the event logging on windows."""
32
33from twisted.trial import unittest
34
35class GetListenerTestCase(unittest.TestCase):
36 """Listener creation tests."""
37
38 def test_never_creates_a_listener(self):
39 """The listener is never created on windows."""
40 from ubuntuone.platform import event_logging
41 listener = event_logging.get_listener(None, None)
42 self.assertEqual(listener, None)
43
440
=== removed directory 'tests/platform/linux/eventlog'
=== removed file 'tests/platform/linux/eventlog/__init__.py'
--- tests/platform/linux/eventlog/__init__.py 2012-04-09 20:07:05 +0000
+++ tests/platform/linux/eventlog/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,27 +0,0 @@
1# Copyright 2010-2012 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14#
15# In addition, as a special exception, the copyright holders give
16# permission to link the code of portions of this program with the
17# OpenSSL library under certain conditions as described in each
18# individual source file, and distribute linked combinations
19# including the two.
20# You must obey the GNU General Public License in all respects
21# for all of the code used other than OpenSSL. If you modify
22# file(s) with this exception, you may extend this exception to your
23# version of the file(s), but you are not obligated to do so. If you
24# do not wish to do so, delete this exception statement from your
25# version. If you delete this exception statement from all source
26# files in the program, then also delete it here.
27"""Tests module."""
280
=== removed file 'tests/platform/linux/eventlog/test_zg_listener.py'
--- tests/platform/linux/eventlog/test_zg_listener.py 2012-10-16 15:13:24 +0000
+++ tests/platform/linux/eventlog/test_zg_listener.py 1970-01-01 00:00:00 +0000
@@ -1,1216 +0,0 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright 2010-2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# In addition, as a special exception, the copyright holders give
18# permission to link the code of portions of this program with the
19# OpenSSL library under certain conditions as described in each
20# individual source file, and distribute linked combinations
21# including the two.
22# You must obey the GNU General Public License in all respects
23# for all of the code used other than OpenSSL. If you modify
24# file(s) with this exception, you may extend this exception to your
25# version of the file(s), but you are not obligated to do so. If you
26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.
29"""Test the event logging from SyncDaemon into Zeitgeist."""
30
31import logging
32import os
33import sys
34import uuid
35
36from os.path import basename
37from twisted.internet import defer
38from zeitgeist.datamodel import Interpretation, Manifestation
39
40# python-zeitgeist on lucid has no mimetypes module, and it's usually
41# disabled, but fake it for running tests on lucid
42try:
43 import zeitgeist.mimetypes
44 assert(zeitgeist.mimetypes is not None) # make pyflakes happy
45except ImportError:
46
47 class FakeMimetypes(object):
48 """A fake zg.mimetypes module."""
49
50 def get_interpretation_for_mimetype(self, mimetype):
51 """This fake always returns AUDIO."""
52 return Interpretation.AUDIO
53
54 sys.modules["zeitgeist.mimetypes"] = FakeMimetypes()
55
56from contrib.testing.testcase import (
57 FakeMain, FakeMainTestCase, BaseTwistedTestCase)
58from ubuntuone.devtools.handlers import MementoHandler
59from ubuntuone.platform import expand_user
60from ubuntuone.storageprotocol import client, delta
61from ubuntuone.storageprotocol.request import ROOT
62from ubuntuone.storageprotocol.sharersp import NotifyShareHolder
63from ubuntuone.syncdaemon.action_queue import (
64 RequestQueue, Upload, MakeFile, MakeDir)
65from ubuntuone.eventlog.zg_listener import (
66 zglog, ZeitgeistListener, ACTOR_UBUNTUONE,
67 EVENT_INTERPRETATION_U1_FOLDER_SHARED,
68 EVENT_INTERPRETATION_U1_FOLDER_UNSHARED,
69 EVENT_INTERPRETATION_U1_SHARE_ACCEPTED,
70 EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED,
71 EVENT_INTERPRETATION_U1_CONFLICT_RENAME,
72 EVENT_INTERPRETATION_U1_UDF_CREATED,
73 EVENT_INTERPRETATION_U1_UDF_DELETED,
74 EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED,
75 EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED,
76 MANIFESTATION_U1_CONTACT_DATA_OBJECT, DIRECTORY_MIMETYPE,
77 INTERPRETATION_U1_CONTACT, URI_PROTOCOL_U1,
78 STORAGE_DELETED, STORAGE_NETWORK, STORAGE_LOCAL)
79from ubuntuone.syncdaemon.sync import Sync
80from ubuntuone.syncdaemon.volume_manager import (
81 ACCESS_LEVEL_RO,
82 get_udf_path, Share, Shared, UDF,
83)
84from tests.syncdaemon.test_action_queue import (
85 ConnectedBaseTestCase,
86 FakeSemaphore,
87 FakeTempFile,
88 TestingProtocol,
89)
90
91VOLUME = uuid.UUID('12345678-1234-1234-1234-123456789abc')
92
93
94class MockLogger(object):
95 """A mock logger that stores whatever is logged into it."""
96
97 def __init__(self):
98 """Initialize this instance."""
99 self.events = []
100 self.deferreds = []
101
102 def log(self, event):
103 """Log the event."""
104 self.events.append(event)
105 if self.deferreds:
106 self.callback_next_deferred(event)
107
108 def callback_next_deferred(self, event):
109 """Pop the next deferred and callback it."""
110 d = self.deferreds.pop()
111 if d:
112 d.callback(event)
113
114
115def listen_for(event_q, event, callback, count=1, collect=False):
116 """Setup a EQ listener for the specified event."""
117 class Listener(object):
118 """A basic listener to handle the pushed event."""
119
120 def __init__(self):
121 self.hits = 0
122 self.events = []
123
124 def _handle_event(self, *args, **kwargs):
125 self.hits += 1
126 if collect:
127 self.events.append((args, kwargs))
128 if self.hits == count:
129 event_q.unsubscribe(self)
130 if collect:
131 callback(self.events)
132 elif kwargs:
133 callback((args, kwargs))
134 else:
135 callback(args)
136
137 listener = Listener()
138 setattr(listener, 'handle_' + event, listener._handle_event)
139 event_q.subscribe(listener)
140 return listener
141
142
143class ZeitgeistListenerTestCase(FakeMainTestCase):
144 """Tests for ZeitgeistListener."""
145
146 @defer.inlineCallbacks
147 def setUp(self):
148 """Initialize this instance."""
149 yield super(ZeitgeistListenerTestCase, self).setUp()
150 self.patch(zglog, "ZeitgeistLogger", MockLogger)
151 self.listener = ZeitgeistListener(self.fs, self.vm)
152 self.event_q.subscribe(self.listener)
153 self.patch(self.event_q, "ignored_base_exception", RuntimeError)
154
155 def _listen_for(self, *args, **kwargs):
156 return listen_for(self.main.event_q, *args, **kwargs)
157
158
159class ZeitgeistSharesTestCase(ZeitgeistListenerTestCase):
160 """Tests for all Share-related zeitgeist events."""
161
162 @defer.inlineCallbacks
163 def test_share_created_with_username_is_logged(self):
164 """A ShareCreated event is logged."""
165 fake_username = "fake user"
166 path = os.path.join(self.vm.root.path, 'shared_path')
167 sample_node_id = "node id"
168 self.main.fs.create(path, "")
169 self.main.fs.set_node_id(path, sample_node_id)
170
171 def fake_create_share(node_id, user, name, access_level, marker, path):
172 """Fake the creation of the share on the server."""
173 self.assertIn(marker, self.vm.marker_share_map)
174 share_id = self.fs.get_by_mdid(marker).share_id
175 self.main.event_q.push('AQ_CREATE_SHARE_OK',
176 share_id=share_id,
177 marker=marker)
178
179 d = defer.Deferred()
180 self._listen_for('AQ_CREATE_SHARE_OK', d.callback, 1, collect=True)
181 self.patch(self.main.action_q, "create_share", fake_create_share)
182 self.vm.create_share(path, fake_username, 'shared_name',
183 ACCESS_LEVEL_RO)
184
185 yield d
186
187 self.assert_folder_shared_is_logged(path, fake_username)
188
189 def test_share_created_with_email_is_logged(self):
190 """A ShareCreated event is logged."""
191 fake_username = "fakeuser@somewhere.com"
192 path = os.path.join(self.vm.root.path, 'shared_path')
193 sample_node_id = "node id"
194 self.main.fs.create(path, "")
195 self.main.fs.set_node_id(path, sample_node_id)
196
197 def fake_create_share(node_id, user, name, access_level, marker, path):
198 """Fake the creation of the share on the server."""
199 self.assertIn(marker, self.vm.marker_share_map)
200 self.main.event_q.push('AQ_SHARE_INVITATION_SENT',
201 marker=marker)
202
203 self.patch(self.main.action_q, "create_share", fake_create_share)
204 self.vm.create_share(path, fake_username, 'shared_name',
205 ACCESS_LEVEL_RO)
206
207 self.assert_folder_shared_is_logged(path, fake_username)
208
209 def assert_folder_shared_is_logged(self, path, fake_username):
210 """Assert that the FolderShared event was logged."""
211
212 self.assertEqual(len(self.listener.zg.events), 1)
213 event = self.listener.zg.events[0]
214 foldername = basename(path)
215
216 self.assertEqual(event.interpretation,
217 EVENT_INTERPRETATION_U1_FOLDER_SHARED)
218 self.assertEqual(event.manifestation,
219 Manifestation.USER_ACTIVITY)
220 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
221
222 folder = event.subjects[0]
223 self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
224 self.assertEqual(folder.interpretation, Interpretation.FOLDER)
225 self.assertEqual(folder.manifestation,
226 Manifestation.REMOTE_DATA_OBJECT)
227 self.assertTrue(folder.origin.endswith(path))
228 self.assertEqual(folder.text, foldername)
229 self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
230 self.assertEqual(folder.storage, STORAGE_NETWORK)
231
232 other_user = event.subjects[1]
233 self.assertEqual(other_user.uri, "mailto:" + fake_username)
234 self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT)
235 self.assertEqual(other_user.manifestation,
236 MANIFESTATION_U1_CONTACT_DATA_OBJECT)
237 self.assertEqual(other_user.text, fake_username)
238
239 @defer.inlineCallbacks
240 def test_share_deleted_is_logged(self):
241 """Test VolumeManager.delete_share."""
242 sample_share_id = "share id"
243 sample_node_id = "node id"
244 fake_username = "fake user"
245 folder_name = "shared_path"
246 path = os.path.join(self.vm.root.path, folder_name)
247 self.main.fs.create(path, "")
248 self.main.fs.set_node_id(path, sample_node_id)
249 share = Shared(path=path, volume_id=sample_share_id,
250 node_id=sample_node_id, other_username=fake_username)
251 yield self.vm.add_shared(share)
252
253 def fake_delete_share(share_id):
254 """Fake delete_share."""
255 self.assertEqual(share_id, share.volume_id)
256 self.main.event_q.push('AQ_DELETE_SHARE_OK', share_id=share_id)
257
258 self.patch(self.main.action_q, 'delete_share', fake_delete_share)
259 d = defer.Deferred()
260 self._listen_for('VM_SHARE_DELETED', d.callback, 1, collect=True)
261 self.vm.delete_share(share.volume_id)
262 yield d
263
264 self.assertEqual(len(self.listener.zg.events), 1)
265 event = self.listener.zg.events[0]
266
267 self.assertEqual(event.interpretation,
268 EVENT_INTERPRETATION_U1_FOLDER_UNSHARED)
269 self.assertEqual(event.manifestation,
270 Manifestation.USER_ACTIVITY)
271 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
272
273 folder = event.subjects[0]
274 self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
275 self.assertEqual(folder.interpretation, Interpretation.FOLDER)
276 self.assertEqual(folder.manifestation,
277 Manifestation.REMOTE_DATA_OBJECT)
278 self.assertTrue(folder.origin.endswith(path))
279 self.assertEqual(folder.text, folder_name)
280 self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
281 self.assertEqual(folder.storage, STORAGE_NETWORK)
282
283 other_user = event.subjects[1]
284 self.assertEqual(other_user.uri, "mailto:" + fake_username)
285 self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT)
286 self.assertEqual(other_user.manifestation,
287 MANIFESTATION_U1_CONTACT_DATA_OBJECT)
288 self.assertEqual(other_user.text, fake_username)
289
290 @defer.inlineCallbacks
291 def test_share_accepted_is_logged(self):
292 """Test that an accepted share event is logged."""
293 # initialize the the root
294 self.vm._got_root('root_uuid')
295 fake_username = "fake user"
296 folder_name = "shared_path"
297 path = os.path.join(self.vm.root.path, folder_name)
298 self.main.fs.create(path, "")
299 share_path = os.path.join(self.shares_dir, folder_name)
300 share = Share(path=share_path, volume_id='volume_id', node_id="node_id",
301 other_username=fake_username)
302 yield self.vm.add_share(share)
303
304 self.assertEqual(len(self.listener.zg.events), 1)
305 event = self.listener.zg.events[0]
306
307 self.assertEqual(event.interpretation,
308 EVENT_INTERPRETATION_U1_SHARE_ACCEPTED)
309 self.assertEqual(event.manifestation,
310 Manifestation.USER_ACTIVITY)
311 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
312
313 folder = event.subjects[0]
314 self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
315 self.assertEqual(folder.interpretation, Interpretation.FOLDER)
316 self.assertEqual(folder.manifestation,
317 Manifestation.REMOTE_DATA_OBJECT)
318 self.assertTrue(folder.origin.endswith(share_path))
319 self.assertEqual(folder.text, folder_name)
320 self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
321 self.assertEqual(folder.storage, STORAGE_NETWORK)
322
323 other_user = event.subjects[1]
324 self.assertEqual(other_user.uri, "mailto:" + fake_username)
325 self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT)
326 self.assertEqual(other_user.manifestation,
327 MANIFESTATION_U1_CONTACT_DATA_OBJECT)
328 self.assertEqual(other_user.text, fake_username)
329
330 @defer.inlineCallbacks
331 def test_share_unaccepted_is_logged(self):
332 """Test that an unaccepted share event is logged."""
333 fake_username = "fake user"
334 folder_name = u"share"
335 d = defer.Deferred()
336
337 share_path = os.path.join(self.main.shares_dir, folder_name)
338 holder = NotifyShareHolder.from_params(uuid.uuid4(),
339 uuid.uuid4(),
340 u'fake_share',
341 fake_username,
342 u'visible_name', 'Read')
343
344 share = Share.from_notify_holder(holder, share_path)
345 yield self.main.vm.add_share(share)
346 self._listen_for('VM_VOLUME_DELETED', d.callback, 1, collect=True)
347 self.main.event_q.push('SV_SHARE_DELETED', share_id=holder.share_id)
348 yield d
349
350 self.assertEqual(len(self.listener.zg.events), 2)
351 event = self.listener.zg.events[1]
352
353 self.assertEqual(event.interpretation,
354 EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED)
355 self.assertEqual(event.manifestation,
356 Manifestation.USER_ACTIVITY)
357 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
358
359 folder = event.subjects[0]
360 self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
361 self.assertEqual(folder.interpretation, Interpretation.FOLDER)
362 self.assertEqual(folder.manifestation,
363 Manifestation.REMOTE_DATA_OBJECT)
364 self.assertTrue(folder.origin.endswith(share_path))
365 self.assertEqual(folder.text, folder_name)
366 self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
367 self.assertEqual(folder.storage, STORAGE_NETWORK)
368
369 other_user = event.subjects[1]
370 self.assertEqual(other_user.uri, "mailto:" + fake_username)
371 self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT)
372 self.assertEqual(other_user.manifestation,
373 MANIFESTATION_U1_CONTACT_DATA_OBJECT)
374 self.assertEqual(other_user.text, fake_username)
375
376
377class ZeitgeistUDFsTestCase(ZeitgeistListenerTestCase):
378 """Tests for all UDFs-related zeitgeist events."""
379
380 def _create_udf(self, id, node_id, suggested_path, subscribed=True):
381 """Create an UDF and returns it and the volume."""
382 path = get_udf_path(suggested_path)
383 # make sure suggested_path is unicode
384 if isinstance(suggested_path, str):
385 suggested_path = suggested_path.decode('utf-8')
386 udf = UDF(str(id), str(node_id), suggested_path, path, subscribed)
387 return udf
388
389 @defer.inlineCallbacks
390 def test_udf_create_is_logged(self):
391 """Test for Folders.create."""
392 folder_name = u'ñoño'.encode('utf-8')
393 path = os.path.join(self.home_dir, folder_name)
394 id = uuid.uuid4()
395 node_id = uuid.uuid4()
396
397 def create_udf(path, name, marker):
398 """Fake create_udf."""
399 # check that the marker is the full path to the udf
400 expanded_path = expand_user(path.encode('utf-8'))
401 udf_path = os.path.join(expanded_path, name.encode('utf-8'))
402 if str(marker) != udf_path:
403 d.errback(ValueError("marker != path - "
404 "marker: %r path: %r" % (marker, udf_path)))
405 self.main.event_q.push("AQ_CREATE_UDF_OK", **dict(volume_id=id,
406 node_id=node_id,
407 marker=marker))
408
409 self.patch(self.main.action_q, "create_udf", create_udf)
410
411 d = defer.Deferred()
412 self.listener.zg.deferreds.append(d)
413 self.vm.create_udf(path)
414 yield d
415
416 self.assertEqual(len(self.listener.zg.events), 1)
417 event = self.listener.zg.events[0]
418
419 self.assertEqual(event.interpretation,
420 EVENT_INTERPRETATION_U1_UDF_CREATED)
421 self.assertEqual(event.manifestation,
422 Manifestation.USER_ACTIVITY)
423 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
424
425 folder = event.subjects[0]
426 self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
427 self.assertEqual(folder.interpretation, Interpretation.FOLDER)
428 self.assertEqual(folder.manifestation,
429 Manifestation.REMOTE_DATA_OBJECT)
430 self.assertTrue(folder.origin.endswith(path))
431 self.assertEqual(folder.text, folder_name)
432 self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
433 self.assertEqual(folder.storage, STORAGE_NETWORK)
434
435 @defer.inlineCallbacks
436 def test_udf_delete_is_logged(self):
437 """Test for Folders.delete."""
438 id = uuid.uuid4()
439 node_id = uuid.uuid4()
440 folder_name = u'ñoño'.encode('utf-8')
441 path = os.path.join(self.home_dir, folder_name)
442
443 d = defer.Deferred()
444 self.listener.zg.deferreds.append(d)
445
446 def create_udf(path, name, marker):
447 """Fake create_udf."""
448 # check that the marker is the full path to the udf
449 expanded_path = expand_user(path.encode('utf-8'))
450 udf_path = os.path.join(expanded_path, name.encode('utf-8'))
451 if str(marker) != udf_path:
452 d.errback(ValueError("marker != path - "
453 "marker: %r path: %r" % (marker, udf_path)))
454 self.main.event_q.push("AQ_CREATE_UDF_OK", **dict(volume_id=id,
455 node_id=node_id,
456 marker=marker))
457
458 self.patch(self.main.action_q, "create_udf", create_udf)
459
460 self.vm.create_udf(path)
461 yield d
462
463 def delete_volume(volume_id, path):
464 """Fake delete_volume."""
465 self.main.event_q.push("AQ_DELETE_VOLUME_OK", volume_id=id)
466
467 self.patch(self.main.action_q, "delete_volume", delete_volume)
468
469 self.assertEqual(len(self.listener.zg.events), 1)
470 event = self.listener.zg.events[0]
471
472 d2 = defer.Deferred()
473 self.listener.zg.deferreds.append(d2)
474 self.vm.delete_volume(str(id))
475 yield d2
476
477 self.assertEqual(len(self.listener.zg.events), 2)
478 event = self.listener.zg.events[1]
479
480 self.assertEqual(event.interpretation,
481 EVENT_INTERPRETATION_U1_UDF_DELETED)
482 self.assertEqual(event.manifestation,
483 Manifestation.USER_ACTIVITY)
484 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
485
486 folder = event.subjects[0]
487 self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1))
488 self.assertEqual(folder.interpretation, Interpretation.FOLDER)
489 self.assertEqual(folder.manifestation,
490 Manifestation.DELETED_RESOURCE)
491 self.assertTrue(folder.origin.endswith(path))
492 self.assertEqual(folder.text, folder_name)
493 self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
494 self.assertEqual(folder.storage, STORAGE_DELETED)
495
496 @defer.inlineCallbacks
497 def test_udf_subscribe_is_logged(self):
498 """Test for Folders.subscribe."""
499 folder_name = u"ñoño"
500 suggested_path = u'~/' + folder_name
501 udf = self._create_udf(uuid.uuid4(), 'node_id', suggested_path,
502 subscribed=False)
503 yield self.main.vm.add_udf(udf)
504 d = defer.Deferred()
505 self.listener.zg.deferreds.append(d)
506 self.vm.subscribe_udf(udf.volume_id)
507 yield d
508
509 self.assertEqual(len(self.listener.zg.events), 2)
510 event = self.listener.zg.events[1]
511
512 self.assertEqual(event.interpretation,
513 EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED)
514 self.assertEqual(event.manifestation,
515 Manifestation.USER_ACTIVITY)
516 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
517
518 folder = event.subjects[0]
519 self.assertTrue(folder.uri.endswith(udf.path))
520 self.assertEqual(folder.interpretation, Interpretation.FOLDER)
521 self.assertEqual(folder.manifestation,
522 Manifestation.FILE_DATA_OBJECT)
523 self.assertTrue(folder.origin.startswith(URI_PROTOCOL_U1))
524 self.assertEqual(folder.text.decode('utf-8'), folder_name)
525 self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
526 self.assertEqual(folder.storage, STORAGE_LOCAL)
527
528 @defer.inlineCallbacks
529 def test_udf_unsubscribe_is_logged(self):
530 """Test for Folders.unsubscribe."""
531 suggested_path = u'~/ñoño'
532 udf = self._create_udf(uuid.uuid4(), 'node_id', suggested_path,
533 subscribed=True)
534 folder_name = basename(udf.path)
535 yield self.main.vm.add_udf(udf)
536 d = defer.Deferred()
537 self._listen_for('VM_UDF_UNSUBSCRIBED', d.callback, 1, collect=True)
538 self.vm.unsubscribe_udf(udf.volume_id)
539 yield d
540
541 self.assertEqual(len(self.listener.zg.events), 2)
542 event = self.listener.zg.events[1]
543
544 self.assertEqual(event.interpretation,
545 EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED)
546 self.assertEqual(event.manifestation,
547 Manifestation.USER_ACTIVITY)
548 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
549
550 folder = event.subjects[0]
551 self.assertTrue(folder.uri.endswith(udf.path))
552 self.assertEqual(folder.interpretation, Interpretation.FOLDER)
553 self.assertEqual(folder.manifestation,
554 Manifestation.DELETED_RESOURCE)
555 self.assertTrue(folder.origin.startswith(URI_PROTOCOL_U1))
556 self.assertEqual(folder.text, folder_name)
557 self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE)
558 self.assertEqual(folder.storage, STORAGE_DELETED)
559
560
561class ZeitgeistRemoteFileSyncTestCase(ConnectedBaseTestCase):
562 """File sync events are logged into Zeitgeist."""
563
564 @defer.inlineCallbacks
565 def setUp(self):
566 """Initialize this test instance."""
567 yield super(ZeitgeistRemoteFileSyncTestCase, self).setUp()
568 self.rq = request_queue = RequestQueue(action_queue=self.action_queue)
569 self.rq.transfers_semaphore = FakeSemaphore()
570
571 class MyUpload(Upload):
572 """Just to allow monkeypatching."""
573
574 self.share_id = ""
575 self.mdid = self.main.fs.create(os.path.join(self.root, 'file'), '')
576 self.command = MyUpload(request_queue, share_id=self.share_id,
577 node_id='a_node_id', previous_hash='prev_hash',
578 hash='yadda', crc32=0, size=0, mdid=self.mdid)
579 self.command.make_logger()
580 self.command.tempfile = FakeTempFile(self.mktemp('tmpdir'))
581 self.fsm = self.action_queue.main.fs
582 self.vm = self.action_queue.main.vm
583 self.patch(zglog, "ZeitgeistLogger", MockLogger)
584 self.listener = ZeitgeistListener(self.fsm, self.vm)
585 self.action_queue.event_queue.subscribe(self.listener)
586 self.root_id = "roootid"
587 self.sync = Sync(main=self.main)
588
589 def test_syncdaemon_creates_file_on_server_is_logged(self):
590 """Files created by SyncDaemon on the server are logged."""
591 filename = "filename.mp3"
592 path = os.path.join(self.vm.root.path, filename)
593 self.fsm.create(path, "")
594 self.fsm.set_node_id(path, "a_node_id")
595
596 request = client.MakeFile(self.action_queue.client, self.share_id,
597 'parent', filename)
598 request.new_id = 'a_node_id'
599 request.new_generation = 13
600
601 # create a command and trigger it success
602 cmd = MakeFile(self.rq, self.share_id, 'parent', filename,
603 'marker', self.mdid)
604 cmd.handle_success(request)
605
606 # create a request and fill it with succesful information
607 aq_client = TestingProtocol()
608 request = client.PutContent(aq_client, self.share_id,
609 'node', 'prvhash', 'newhash', 'crc32',
610 'size', 'deflated', 'fd')
611 request.new_generation = 13
612
613 # trigger success in the command
614 self.command.handle_success(request)
615
616 # check for successful event
617 kwargs = dict(share_id=self.command.share_id, node_id='a_node_id',
618 hash='yadda', new_generation=13)
619
620 info = dict(marker='marker', new_id='a_node_id', new_generation=13,
621 volume_id=self.share_id)
622 events = [
623 ('AQ_FILE_NEW_OK', info),
624 ('AQ_UPLOAD_FINISHED', kwargs),
625 ]
626 self.assertEqual(events, self.command.action_queue.event_queue.events)
627
628 self.assertEqual(len(self.listener.zg.events), 1)
629 event = self.listener.zg.events[0]
630
631 self.assertEqual(event.interpretation,
632 Interpretation.CREATE_EVENT)
633 self.assertEqual(event.manifestation,
634 Manifestation.SCHEDULED_ACTIVITY)
635 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
636
637 remote_file = event.subjects[0]
638 self.assertTrue(remote_file.uri.startswith(URI_PROTOCOL_U1))
639 self.assertEqual(remote_file.interpretation, Interpretation.AUDIO)
640 self.assertEqual(remote_file.manifestation,
641 Manifestation.REMOTE_DATA_OBJECT)
642 self.assertTrue(remote_file.origin.endswith(filename))
643 self.assertEqual(remote_file.text, filename)
644 self.assertEqual(remote_file.mimetype, "audio/mpeg")
645 self.assertEqual(remote_file.storage, STORAGE_NETWORK)
646
647 def test_syncdaemon_creates_dir_on_server_is_logged(self):
648 """Dirs created by SyncDaemon on the server are logged."""
649 dirname = "dirname"
650 path = os.path.join(self.vm.root.path, dirname)
651 self.fsm.create(path, "")
652 self.fsm.set_node_id(path, "a_node_id")
653
654 request = client.MakeDir(self.action_queue.client, self.share_id,
655 'parent', dirname)
656 request.new_id = 'a_node_id'
657 request.new_generation = 13
658
659 # create a command and trigger it success
660 cmd = MakeDir(self.rq, self.share_id, 'parent',
661 dirname, 'marker', self.mdid)
662 cmd.handle_success(request)
663
664 # check for successful event
665 info = dict(marker='marker', new_id='a_node_id', new_generation=13,
666 volume_id=self.share_id)
667 events = [('AQ_DIR_NEW_OK', info)]
668 self.assertEqual(events, self.command.action_queue.event_queue.events)
669
670 self.assertEqual(len(self.listener.zg.events), 1)
671 event = self.listener.zg.events[0]
672
673 self.assertEqual(event.interpretation,
674 Interpretation.CREATE_EVENT)
675 self.assertEqual(event.manifestation,
676 Manifestation.SCHEDULED_ACTIVITY)
677 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
678
679 remote_folder = event.subjects[0]
680 self.assertTrue(remote_folder.uri.startswith(URI_PROTOCOL_U1))
681 self.assertEqual(remote_folder.interpretation, Interpretation.FOLDER)
682 self.assertEqual(remote_folder.manifestation,
683 Manifestation.REMOTE_DATA_OBJECT)
684 self.assertTrue(remote_folder.origin.endswith(dirname))
685 self.assertEqual(remote_folder.text, dirname)
686 self.assertEqual(remote_folder.mimetype, DIRECTORY_MIMETYPE)
687 self.assertEqual(remote_folder.storage, STORAGE_NETWORK)
688
689 def test_syncdaemon_modifies_on_server_is_logged(self):
690 """Files modified by SyncDaemon on the server are logged."""
691 filename = "filename.mp3"
692 path = os.path.join(self.vm.root.path, filename)
693 self.fsm.create(path, "")
694 self.fsm.set_node_id(path, "a_node_id")
695
696 # create a request and fill it with succesful information
697 aq_client = TestingProtocol()
698 request = client.PutContent(aq_client, self.share_id,
699 'node', 'prvhash', 'newhash', 'crc32',
700 'size', 'deflated', 'fd')
701 request.new_generation = 13
702
703 # trigger success in the command
704 self.command.handle_success(request)
705
706 # check for successful event
707 kwargs = dict(share_id=self.command.share_id, node_id='a_node_id',
708 hash='yadda', new_generation=13)
709
710 events = [('AQ_UPLOAD_FINISHED', kwargs)]
711 self.assertEqual(events, self.command.action_queue.event_queue.events)
712
713 self.assertEqual(len(self.listener.zg.events), 1)
714 event = self.listener.zg.events[0]
715
716 self.assertEqual(event.interpretation,
717 Interpretation.MODIFY_EVENT)
718 self.assertEqual(event.manifestation,
719 Manifestation.SCHEDULED_ACTIVITY)
720 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
721
722 remote_file = event.subjects[0]
723 self.assertTrue(remote_file.uri.startswith(URI_PROTOCOL_U1))
724 self.assertEqual(remote_file.interpretation, Interpretation.AUDIO)
725 self.assertEqual(remote_file.manifestation,
726 Manifestation.REMOTE_DATA_OBJECT)
727 self.assertTrue(remote_file.origin.endswith(filename))
728 self.assertEqual(remote_file.text, filename)
729 self.assertEqual(remote_file.mimetype, "audio/mpeg")
730 self.assertEqual(remote_file.storage, STORAGE_NETWORK)
731
732 @defer.inlineCallbacks
733 def test_syncdaemon_deletes_file_on_server_is_logged(self):
734 """Files deleted by SD on the server are logged."""
735 file_name = "filename.mp3"
736 d = defer.Deferred()
737 listen_for(self.main.event_q, 'AQ_UNLINK_OK', d.callback)
738
739 path = os.path.join(self.main.vm.root.path, "filename.mp3")
740 self.main.event_q.push("AQ_UNLINK_OK", share_id="",
741 parent_id="parent_id",
742 node_id="node_id", new_generation=13,
743 was_dir=False, old_path=path)
744 yield d
745
746 self.assertEqual(len(self.listener.zg.events), 1)
747 event = self.listener.zg.events[0]
748
749 self.assertEqual(event.interpretation,
750 Interpretation.DELETE_EVENT)
751 self.assertEqual(event.manifestation,
752 Manifestation.SCHEDULED_ACTIVITY)
753 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
754
755 remote_file = event.subjects[0]
756 self.assertTrue(remote_file.uri.startswith(URI_PROTOCOL_U1))
757 self.assertEqual(remote_file.interpretation, Interpretation.AUDIO)
758 self.assertEqual(remote_file.manifestation,
759 Manifestation.DELETED_RESOURCE)
760 self.assertTrue(remote_file.origin.endswith(file_name))
761 self.assertEqual(remote_file.text, file_name)
762 self.assertEqual(remote_file.mimetype, "audio/mpeg")
763 self.assertEqual(remote_file.storage, STORAGE_DELETED)
764
765 @defer.inlineCallbacks
766 def test_syncdaemon_deletes_dir_on_server_is_logged(self):
767 """Directories deleted by SD on the server are logged."""
768 folder_name = "folder name"
769 d = defer.Deferred()
770 listen_for(self.main.event_q, 'AQ_UNLINK_OK', d.callback)
771
772 path = os.path.join(self.main.vm.root.path, "folder name")
773 self.main.event_q.push("AQ_UNLINK_OK", share_id="",
774 parent_id="parent_id",
775 node_id="node_id", new_generation=13,
776 was_dir=True, old_path=path)
777 yield d
778
779 self.assertEqual(len(self.listener.zg.events), 1)
780 event = self.listener.zg.events[0]
781
782 self.assertEqual(event.interpretation,
783 Interpretation.DELETE_EVENT)
784 self.assertEqual(event.manifestation,
785 Manifestation.SCHEDULED_ACTIVITY)
786 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
787
788 remote_folder = event.subjects[0]
789 self.assertTrue(remote_folder.uri.startswith(URI_PROTOCOL_U1))
790 self.assertEqual(remote_folder.interpretation, Interpretation.FOLDER)
791 self.assertEqual(remote_folder.manifestation,
792 Manifestation.DELETED_RESOURCE)
793 self.assertTrue(remote_folder.origin.endswith(folder_name))
794 self.assertEqual(remote_folder.text, folder_name)
795 self.assertEqual(remote_folder.mimetype, DIRECTORY_MIMETYPE)
796 self.assertEqual(remote_folder.storage, STORAGE_DELETED)
797
798
799class ZeitgeistLocalFileSyncTestCase(BaseTwistedTestCase):
800 """Zeitgeist events coming from the server."""
801 timeout = 5
802
803 @defer.inlineCallbacks
804 def setUp(self):
805 """Initialize this instance."""
806 yield super(ZeitgeistLocalFileSyncTestCase, self).setUp()
807 self.root = self.mktemp('root')
808 self.shares = self.mktemp('shares')
809 self.data = self.mktemp('data')
810 self.partials_dir = self.mktemp('partials_dir')
811 self.handler = MementoHandler()
812 self.handler.setLevel(logging.ERROR)
813 FakeMain._sync_class = Sync
814 self.main = FakeMain(root_dir=self.root, shares_dir=self.shares,
815 data_dir=self.data,
816 partials_dir=self.partials_dir)
817 self._logger = logging.getLogger('ubuntuone.SyncDaemon')
818 self._logger.addHandler(self.handler)
819
820 self.root_id = root_id = "roootid"
821 self.main.vm._got_root(root_id)
822 self.filemp3delta = delta.FileInfoDelta(
823 generation=5, is_live=True, file_type=delta.FILE,
824 parent_id=self.root_id, share_id=ROOT, node_id=uuid.uuid4(),
825 name=u"fileñ.mp3", is_public=False, content_hash="hash",
826 crc32=1, size=10, last_modified=0)
827
828 self.dirdelta = delta.FileInfoDelta(
829 generation=6, is_live=True, file_type=delta.DIRECTORY,
830 parent_id=root_id, share_id=ROOT, node_id=uuid.uuid4(),
831 name=u"directory_ñ", is_public=False, content_hash="hash",
832 crc32=1, size=10, last_modified=0)
833
834 self.patch(zglog, "ZeitgeistLogger", MockLogger)
835 self.listener = ZeitgeistListener(self.main.fs, self.main.vm)
836 self.main.event_q.subscribe(self.listener)
837
838 @defer.inlineCallbacks
839 def tearDown(self):
840 """Clean up this instance."""
841 self._logger.removeHandler(self.handler)
842 self.main.shutdown()
843 FakeMain._sync_class = None
844 for record in self.handler.records:
845 exc_info = getattr(record, 'exc_info', None)
846 if exc_info is not None:
847 raise exc_info[0], exc_info[1], exc_info[2]
848 yield super(ZeitgeistLocalFileSyncTestCase, self).tearDown()
849
850 @defer.inlineCallbacks
851 def test_syncdaemon_creates_file_locally_is_logged(self):
852 """Files created locally by SyncDaemon are logged."""
853 file_name = self.filemp3delta.name.encode('utf8')
854 d = defer.Deferred()
855 d2 = defer.Deferred()
856 listen_for(self.main.event_q, 'SV_FILE_NEW', d.callback)
857 listen_for(self.main.event_q, 'AQ_DOWNLOAD_FINISHED', d2.callback)
858
859 deltas = [self.filemp3delta]
860 kwargs = dict(volume_id=ROOT, delta_content=deltas, end_generation=11,
861 full=True, free_bytes=10)
862 self.main.sync.handle_AQ_DELTA_OK(**kwargs)
863
864 # check that the file is created
865 node = self.main.fs.get_by_node_id(ROOT, self.filemp3delta.node_id)
866 self.assertEqual(node.path, file_name)
867 self.assertEqual(node.is_dir, False)
868 self.assertEqual(node.generation, self.filemp3delta.generation)
869
870 yield d # wait for SV_FILE_NEW
871
872 dlargs = dict(
873 share_id=self.filemp3delta.share_id,
874 node_id=self.filemp3delta.node_id,
875 server_hash="server hash")
876 self.main.event_q.push("AQ_DOWNLOAD_FINISHED", **dlargs)
877
878 yield d2 # wait for AQ_DOWNLOAD_FINISHED
879
880 self.assertEqual(len(self.listener.zg.events), 1)
881 event = self.listener.zg.events[0]
882
883 self.assertEqual(event.interpretation,
884 Interpretation.CREATE_EVENT)
885 self.assertEqual(event.manifestation,
886 Manifestation.WORLD_ACTIVITY)
887 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
888
889 local_file = event.subjects[0]
890 self.assertTrue(local_file.uri.endswith(file_name))
891 self.assertEqual(local_file.interpretation, Interpretation.AUDIO)
892 self.assertEqual(local_file.manifestation,
893 Manifestation.FILE_DATA_OBJECT)
894 self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1))
895 self.assertEqual(local_file.text, file_name)
896 self.assertEqual(local_file.mimetype, "audio/mpeg")
897 self.assertEqual(local_file.storage, STORAGE_LOCAL)
898
899 @defer.inlineCallbacks
900 def test_syncdaemon_creates_dir_locally_is_logged(self):
901 """Dirs created locally by SyncDaemon are logged."""
902 folder_name = self.dirdelta.name.encode('utf8')
903 d = defer.Deferred()
904 listen_for(self.main.event_q, 'SV_DIR_NEW', d.callback)
905
906 deltas = [self.dirdelta]
907 kwargs = dict(volume_id=ROOT, delta_content=deltas, end_generation=11,
908 full=True, free_bytes=10)
909 self.main.sync.handle_AQ_DELTA_OK(**kwargs)
910
911 # check that the dir is created
912 node = self.main.fs.get_by_node_id(ROOT, self.dirdelta.node_id)
913 self.assertEqual(node.path, folder_name)
914 self.assertEqual(node.is_dir, True)
915 self.assertEqual(node.generation, self.dirdelta.generation)
916
917 yield d # wait for SV_DIR_NEW
918
919 self.assertEqual(len(self.listener.zg.events), 1)
920 event = self.listener.zg.events[0]
921
922 self.assertEqual(event.interpretation,
923 Interpretation.CREATE_EVENT)
924 self.assertEqual(event.manifestation,
925 Manifestation.WORLD_ACTIVITY)
926 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
927
928 local_folder = event.subjects[0]
929 self.assertTrue(local_folder.uri.endswith(folder_name))
930 self.assertEqual(local_folder.interpretation, Interpretation.FOLDER)
931 self.assertEqual(local_folder.manifestation,
932 Manifestation.FILE_DATA_OBJECT)
933 self.assertTrue(local_folder.origin.startswith(URI_PROTOCOL_U1))
934 self.assertEqual(local_folder.text, folder_name)
935 self.assertEqual(local_folder.mimetype, DIRECTORY_MIMETYPE)
936 self.assertEqual(local_folder.storage, STORAGE_LOCAL)
937
938 @defer.inlineCallbacks
939 def test_syncdaemon_modifies_locally_is_logged(self):
940 """Files modified locally by SyncDaemon are logged."""
941 file_name = self.filemp3delta.name.encode('utf8')
942 d = defer.Deferred()
943 d2 = defer.Deferred()
944 listen_for(self.main.event_q, 'SV_FILE_NEW', d.callback)
945 listen_for(self.main.event_q, 'AQ_DOWNLOAD_FINISHED', d2.callback)
946
947 deltas = [self.filemp3delta]
948 kwargs = dict(volume_id=ROOT, delta_content=deltas, end_generation=11,
949 full=True, free_bytes=10)
950 self.main.sync.handle_AQ_DELTA_OK(**kwargs)
951
952 # check that the file is modified
953 node = self.main.fs.get_by_node_id(ROOT, self.filemp3delta.node_id)
954 self.assertEqual(node.path, file_name)
955 self.assertEqual(node.is_dir, False)
956 self.assertEqual(node.generation, self.filemp3delta.generation)
957
958 yield d # wait for SV_FILE_NEW
959
960 # remove from the recent list
961 local_file_id = (self.filemp3delta.share_id, self.filemp3delta.node_id)
962 self.listener.newly_created_local_files.remove(local_file_id)
963
964 dlargs = dict(
965 share_id=self.filemp3delta.share_id,
966 node_id=self.filemp3delta.node_id,
967 server_hash="server hash")
968 self.main.event_q.push("AQ_DOWNLOAD_FINISHED", **dlargs)
969
970 yield d2 # wait for AQ_DOWNLOAD_FINISHED
971
972 self.assertEqual(len(self.listener.zg.events), 1)
973 event = self.listener.zg.events[0]
974
975 self.assertEqual(event.interpretation,
976 Interpretation.MODIFY_EVENT)
977 self.assertEqual(event.manifestation,
978 Manifestation.WORLD_ACTIVITY)
979 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
980
981 local_file = event.subjects[0]
982 self.assertTrue(local_file.uri.endswith(file_name))
983 self.assertEqual(local_file.interpretation, Interpretation.AUDIO)
984 self.assertEqual(local_file.manifestation,
985 Manifestation.FILE_DATA_OBJECT)
986 self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1))
987 self.assertEqual(local_file.text, file_name)
988 self.assertEqual(local_file.mimetype, "audio/mpeg")
989 self.assertEqual(local_file.storage, STORAGE_LOCAL)
990
991 @defer.inlineCallbacks
992 def test_syncdaemon_deletes_file_locally_is_logged(self):
993 """Files deleted locally by SyncDaemon are logged."""
994 file_name = self.filemp3delta.name.encode("utf-8")
995 d = defer.Deferred()
996 listen_for(self.main.event_q, 'SV_FILE_DELETED', d.callback)
997
998 filename = self.filemp3delta.name.encode("utf-8")
999 path = os.path.join(self.main.vm.root.path, filename)
1000 self.main.event_q.push("SV_FILE_DELETED", volume_id="",
1001 node_id="node_id", was_dir=False,
1002 old_path=path)
1003 yield d
1004
1005 self.assertEqual(len(self.listener.zg.events), 1)
1006 event = self.listener.zg.events[0]
1007
1008 self.assertEqual(event.interpretation,
1009 Interpretation.DELETE_EVENT)
1010 self.assertEqual(event.manifestation,
1011 Manifestation.WORLD_ACTIVITY)
1012 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1013
1014 local_file = event.subjects[0]
1015 self.assertTrue(local_file.uri.endswith(file_name))
1016 self.assertEqual(local_file.interpretation, Interpretation.AUDIO)
1017 self.assertEqual(local_file.manifestation,
1018 Manifestation.DELETED_RESOURCE)
1019 self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1))
1020 self.assertEqual(local_file.text, file_name)
1021 self.assertEqual(local_file.mimetype, "audio/mpeg")
1022 self.assertEqual(local_file.storage, STORAGE_DELETED)
1023
1024 @defer.inlineCallbacks
1025 def test_syncdaemon_deletes_dir_locally_is_logged(self):
1026 """Dirs deleted locally by SyncDaemon are logged."""
1027 folder_name = "folder name"
1028 d = defer.Deferred()
1029 listen_for(self.main.event_q, 'SV_FILE_DELETED', d.callback)
1030
1031 path = os.path.join(self.main.vm.root.path, "folder name")
1032 self.main.event_q.push("SV_FILE_DELETED", volume_id="",
1033 node_id="node_id", was_dir=True,
1034 old_path=path)
1035
1036 yield d
1037
1038 self.assertEqual(len(self.listener.zg.events), 1)
1039 event = self.listener.zg.events[0]
1040
1041 self.assertEqual(event.interpretation,
1042 Interpretation.DELETE_EVENT)
1043 self.assertEqual(event.manifestation,
1044 Manifestation.WORLD_ACTIVITY)
1045 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1046
1047 local_folder = event.subjects[0]
1048 self.assertTrue(local_folder.uri.endswith(folder_name))
1049 self.assertEqual(local_folder.interpretation, Interpretation.FOLDER)
1050 self.assertEqual(local_folder.manifestation,
1051 Manifestation.DELETED_RESOURCE)
1052 self.assertTrue(local_folder.origin.startswith(URI_PROTOCOL_U1))
1053 self.assertEqual(local_folder.text, folder_name)
1054 self.assertEqual(local_folder.mimetype, DIRECTORY_MIMETYPE)
1055 self.assertEqual(local_folder.storage, STORAGE_DELETED)
1056
1057 @defer.inlineCallbacks
1058 def test_file_sync_conflict_is_logged(self):
1059 """Files renamed because of conflict are logged."""
1060 file_name = "sample.mp3"
1061 d = defer.Deferred()
1062 listen_for(self.main.event_q, 'FSM_FILE_CONFLICT', d.callback)
1063
1064 testfile = os.path.join(self.main.vm.root.path, file_name)
1065 mdid = self.main.fs.create(testfile, "")
1066 self.main.fs.set_node_id(testfile, "uuid")
1067 with open(testfile, "w") as fh:
1068 fh.write("this is music!")
1069
1070 self.main.fs.move_to_conflict(mdid)
1071
1072 yield d
1073
1074 self.assertEqual(len(self.listener.zg.events), 1)
1075 event = self.listener.zg.events[0]
1076
1077 self.assertEqual(event.interpretation,
1078 EVENT_INTERPRETATION_U1_CONFLICT_RENAME)
1079 self.assertEqual(event.manifestation,
1080 Manifestation.WORLD_ACTIVITY)
1081 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1082
1083 local_file = event.subjects[0]
1084 new_name = testfile + self.main.fs.CONFLICT_SUFFIX
1085 self.assertTrue(local_file.uri.endswith(new_name))
1086 self.assertEqual(local_file.interpretation, Interpretation.AUDIO)
1087 self.assertEqual(local_file.manifestation,
1088 Manifestation.FILE_DATA_OBJECT)
1089 self.assertTrue(local_file.origin.endswith(testfile))
1090 self.assertEqual(local_file.text,
1091 file_name + self.main.fs.CONFLICT_SUFFIX)
1092 self.assertEqual(local_file.mimetype, "audio/mpeg")
1093 self.assertEqual(local_file.storage, STORAGE_LOCAL)
1094
1095 @defer.inlineCallbacks
1096 def test_dir_sync_conflict_is_logged(self):
1097 """Dirs renamed because of conflict are logged."""
1098 folder_name = "sampledir"
1099 d = defer.Deferred()
1100 listen_for(self.main.event_q, 'FSM_DIR_CONFLICT', d.callback)
1101
1102 testdir = os.path.join(self.main.vm.root.path, folder_name)
1103 mdid = self.main.fs.create(testdir, "", is_dir=True)
1104 self.main.fs.set_node_id(testdir, "uuid")
1105 os.mkdir(testdir)
1106
1107 self.main.fs.move_to_conflict(mdid)
1108
1109 yield d
1110
1111 self.assertEqual(len(self.listener.zg.events), 1)
1112 event = self.listener.zg.events[0]
1113
1114 self.assertEqual(event.interpretation,
1115 EVENT_INTERPRETATION_U1_CONFLICT_RENAME)
1116 self.assertEqual(event.manifestation,
1117 Manifestation.WORLD_ACTIVITY)
1118 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1119
1120 local_folder = event.subjects[0]
1121 new_name = testdir + self.main.fs.CONFLICT_SUFFIX
1122 self.assertTrue(local_folder.uri.endswith(new_name))
1123 self.assertEqual(local_folder.interpretation, Interpretation.FOLDER)
1124 self.assertEqual(local_folder.manifestation,
1125 Manifestation.FILE_DATA_OBJECT)
1126 self.assertTrue(local_folder.origin.endswith(testdir))
1127 self.assertEqual(local_folder.text,
1128 folder_name + self.main.fs.CONFLICT_SUFFIX)
1129 self.assertEqual(local_folder.mimetype, DIRECTORY_MIMETYPE)
1130 self.assertEqual(local_folder.storage, STORAGE_LOCAL)
1131
1132
1133class ZeitgeistPublicFilesTestCase(ZeitgeistListenerTestCase):
1134 """Public files events are logged into Zeitgeist."""
1135
1136 @defer.inlineCallbacks
1137 def test_publish_url_is_logged(self):
1138 """Publishing a file with a url is logged."""
1139 share_id = "share"
1140 node_id = "node_id"
1141 is_public = True
1142 public_url = 'http://example.com/foo.mp3'
1143
1144 share_path = os.path.join(self.shares_dir, 'share')
1145 yield self.main.vm.add_share(Share(path=share_path, volume_id='share',
1146 other_username='other username'))
1147 path = os.path.join(share_path, "foo.mp3")
1148 self.main.fs.create(path, str(share_id))
1149 self.main.fs.set_node_id(path, str(node_id))
1150
1151 d = defer.Deferred()
1152 self._listen_for('AQ_CHANGE_PUBLIC_ACCESS_OK', d.callback)
1153 self.main.event_q.push('AQ_CHANGE_PUBLIC_ACCESS_OK',
1154 share_id=share_id, node_id=node_id,
1155 is_public=is_public, public_url=public_url)
1156 yield d
1157
1158 self.assertEqual(len(self.listener.zg.events), 2)
1159 event = self.listener.zg.events[1]
1160
1161 self.assertEqual(event.interpretation,
1162 Interpretation.CREATE_EVENT)
1163 self.assertEqual(event.manifestation,
1164 Manifestation.USER_ACTIVITY)
1165 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1166
1167 public_file = event.subjects[0]
1168 self.assertEqual(public_file.uri, public_url)
1169 self.assertEqual(public_file.interpretation, Interpretation.AUDIO)
1170 self.assertEqual(public_file.manifestation,
1171 Manifestation.REMOTE_DATA_OBJECT)
1172 self.assertTrue(public_file.origin.endswith(node_id))
1173 self.assertEqual(public_file.text, public_url)
1174 self.assertEqual(public_file.mimetype, "audio/mpeg")
1175 self.assertEqual(public_file.storage, STORAGE_NETWORK)
1176
1177 @defer.inlineCallbacks
1178 def test_unpublish_url_is_logged(self):
1179 """Unpublishing a file with a url is logged."""
1180 share_id = "share"
1181 node_id = "node_id"
1182 is_public = False
1183 public_url = 'http://example.com/foo.mp3'
1184
1185 share_path = os.path.join(self.shares_dir, 'share')
1186 yield self.main.vm.add_share(Share(path=share_path, volume_id='share',
1187 other_username='other username'))
1188 path = os.path.join(share_path, "foo.mp3")
1189 self.main.fs.create(path, str(share_id))
1190 self.main.fs.set_node_id(path, str(node_id))
1191
1192 d = defer.Deferred()
1193 self._listen_for('AQ_CHANGE_PUBLIC_ACCESS_OK', d.callback)
1194 self.main.event_q.push('AQ_CHANGE_PUBLIC_ACCESS_OK',
1195 share_id=share_id, node_id=node_id,
1196 is_public=is_public, public_url=public_url)
1197 yield d
1198
1199 self.assertEqual(len(self.listener.zg.events), 2)
1200 event = self.listener.zg.events[1]
1201
1202 self.assertEqual(event.interpretation,
1203 Interpretation.DELETE_EVENT)
1204 self.assertEqual(event.manifestation,
1205 Manifestation.USER_ACTIVITY)
1206 self.assertEqual(event.actor, ACTOR_UBUNTUONE)
1207
1208 public_file = event.subjects[0]
1209 self.assertEqual(public_file.uri, public_url)
1210 self.assertEqual(public_file.interpretation, Interpretation.AUDIO)
1211 self.assertEqual(public_file.manifestation,
1212 Manifestation.DELETED_RESOURCE)
1213 self.assertTrue(public_file.origin.endswith(node_id))
1214 self.assertEqual(public_file.text, public_url)
1215 self.assertEqual(public_file.mimetype, "audio/mpeg")
1216 self.assertEqual(public_file.storage, STORAGE_DELETED)
12170
=== removed file 'tests/platform/linux/eventlog/test_zglog.py'
--- tests/platform/linux/eventlog/test_zglog.py 2012-04-30 14:24:55 +0000
+++ tests/platform/linux/eventlog/test_zglog.py 1970-01-01 00:00:00 +0000
@@ -1,174 +0,0 @@
1# -*- coding: utf-8 -*-
2#
3# Author: Alejandro J. Cura <alecu@canonical.com>
4#
5# Copyright 2010-2012 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19# In addition, as a special exception, the copyright holders give
20# permission to link the code of portions of this program with the
21# OpenSSL library under certain conditions as described in each
22# individual source file, and distribute linked combinations
23# including the two.
24# You must obey the GNU General Public License in all respects
25# for all of the code used other than OpenSSL. If you modify
26# file(s) with this exception, you may extend this exception to your
27# version of the file(s), but you are not obligated to do so. If you
28# do not wish to do so, delete this exception statement from your
29# version. If you delete this exception statement from all source
30# files in the program, then also delete it here.
31"""Tests for the Zeitgeist logging."""
32
33import os
34import shutil
35import subprocess
36import tempfile
37import time
38
39from distutils.spawn import find_executable
40
41from twisted.internet import defer
42from zeitgeist.client import ZeitgeistClient
43from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation
44
45from tests.platform.ipc.test_linux import DBusTwistedTestCase
46from ubuntuone.eventlog.zglog import ZeitgeistLogger
47
48SRCDIR = os.environ.get('SRCDIR', os.getcwd())
49
50
51class NotFoundError(Exception):
52 """Not found error."""
53
54
55class ZeitgeistNotStartedTests(DBusTwistedTestCase):
56 """Tests for the zeitgeist logging module."""
57
58 def test_log_does_not_err_when_daemon_not_started(self):
59 """zeitgeist-daemon was not started."""
60 timestamp = int(time.time() * 1000)
61 subject = Subject.new_for_values(
62 uri="file:///tmp/folder1",
63 interpretation=Interpretation.FOLDER,
64 manifestation=Manifestation.FILE_DATA_OBJECT,
65 origin="ubuntuone:uuid",
66 mimetype="inode/directory",
67 text="sample folder"
68 )
69 sample_event = Event.new_for_values(
70 timestamp=timestamp,
71 interpretation=Interpretation.ACCESS_EVENT,
72 manifestation=Manifestation.USER_ACTIVITY,
73 actor="mailto:sample_subject",
74 subjects=[subject]
75 )
76
77 zg = ZeitgeistLogger()
78 d = zg.log(sample_event)
79 self.assertEqual(zg.client, None)
80
81 def verify(result):
82 """Stored result is the empty list, because zg not available."""
83 self.assertEqual(result, [])
84 return result
85
86 d.addCallback(verify)
87 return d
88
89
90def wait_zeitgeist_started(seconds=10):
91 """Wait a few seconds until zg is started, or fail if it can't."""
92 client = None
93 count = 0
94 while client is None:
95 count += 1
96 try:
97 client = ZeitgeistClient()
98 break
99 except RuntimeError:
100 if count > seconds * 10:
101 raise
102 time.sleep(0.1)
103
104
105class ZeitgeistTestCase(DBusTwistedTestCase):
106 """Tests for the zeitgeist logging module."""
107
108 @defer.inlineCallbacks
109 def setUp(self):
110 yield super(ZeitgeistTestCase, self).setUp()
111 zgdaemon = find_executable("zeitgeist-daemon")
112 if not zgdaemon:
113 raise NotFoundError("zeitgeist-daemon was not found.")
114
115 tempfolder = tempfile.mkdtemp(prefix="test-u1-zeitgeist-")
116 tempstdout = tempfile.TemporaryFile(prefix="test-u1-stdout-")
117 tempstderr = tempfile.TemporaryFile(prefix="test-u1-stderr-")
118 os.environ["ZEITGEIST_DATA_PATH"] = tempfolder
119 p = subprocess.Popen([zgdaemon], bufsize=4096, stdout=tempstdout,
120 stderr=tempstderr)
121
122 def cleanup():
123 """Wait for the process to finish."""
124 p.terminate()
125 p.wait()
126 del(os.environ["ZEITGEIST_DATA_PATH"])
127 shutil.rmtree(tempfolder)
128
129 wait_zeitgeist_started()
130 self.addCleanup(cleanup)
131
132 def test_log_records_the_event(self):
133 """The log method records the event in zg."""
134 timestamp = int(time.time() * 1000)
135 subject = Subject.new_for_values(
136 uri="file:///tmp/folder1",
137 interpretation=Interpretation.FOLDER,
138 manifestation=Manifestation.FILE_DATA_OBJECT,
139 origin="ubuntuone:uuid",
140 mimetype="inode/directory",
141 text="sample folder"
142 )
143 sample_event = Event.new_for_values(
144 timestamp=timestamp,
145 interpretation=Interpretation.ACCESS_EVENT,
146 manifestation=Manifestation.USER_ACTIVITY,
147 actor="mailto:sample_subject",
148 subjects=[subject]
149 )
150
151 sample_template = Event.new_for_values()
152
153 zg = ZeitgeistLogger()
154 self.assertNotEqual(zg.client, None)
155
156 d2 = defer.Deferred()
157
158 def logged(id_list):
159 """The event was logged to zeitgeist."""
160
161 def events_found(event_list):
162 """zg returned the list of events."""
163 self.assertEqual(event_list[0].id, id_list[0])
164 d2.callback("ok")
165
166 zg.client.find_events_for_template(sample_template, events_found)
167
168 d = zg.log(sample_event)
169 d.addCallbacks(logged, d2.errback)
170
171 return d2
172
173
174ZeitgeistTestCase.skip = 'Suite is hanging in nightlies build (LP: #929812).'
1750
=== modified file 'tests/syncdaemon/test_main.py'
--- tests/syncdaemon/test_main.py 2013-01-16 23:57:30 +0000
+++ tests/syncdaemon/test_main.py 2013-02-04 16:10:53 +0000
@@ -83,8 +83,6 @@
83 self.partials_dir = self.mktemp('partials_dir')83 self.partials_dir = self.mktemp('partials_dir')
8484
85 self.patch(main_mod, 'SyncdaemonService', FakedExternalInterface)85 self.patch(main_mod, 'SyncdaemonService', FakedExternalInterface)
86 # no event logger by default
87 self.patch(main_mod.event_logging, "get_listener", lambda *a: None)
88 # no status listener by default86 # no status listener by default
89 self.patch(main_mod.status_listener, "get_listener", lambda *a: None)87 self.patch(main_mod.status_listener, "get_listener", lambda *a: None)
9088
@@ -257,18 +255,6 @@
257 s.add(x)255 s.add(x)
258 return s256 return s
259257
260 def test_event_logger_starts_if_available(self):
261 """The event logger is started if available."""
262 self.patch(main_mod.event_logging,
263 "get_listener", lambda *a: FakeListener())
264 main = self.build_main()
265 self.assertIn(main.eventlog_listener, self._get_listeners(main))
266
267 def test_event_logger_not_started_if_not_available(self):
268 """The event logger is not started if it's not available."""
269 main = self.build_main()
270 self.assertNotIn(main.eventlog_listener, self._get_listeners(main))
271
272 def test_status_listener_is_installed(self):258 def test_status_listener_is_installed(self):
273 """The status listener is installed if needed."""259 """The status listener is installed if needed."""
274 self.patch(main_mod.status_listener,260 self.patch(main_mod.status_listener,
275261
=== modified file 'tests/syncdaemon/test_status_listener.py'
--- tests/syncdaemon/test_status_listener.py 2012-09-20 18:04:58 +0000
+++ tests/syncdaemon/test_status_listener.py 2013-02-04 16:10:53 +0000
@@ -54,12 +54,6 @@
54 self.assertEqual(listener.vm, vm)54 self.assertEqual(listener.vm, vm)
55 self.assertNotEqual(listener.status_frontend, None)55 self.assertNotEqual(listener.status_frontend, None)
5656
57 def test_zeitgeist_not_installed_returns_none(self):
58 """get_listener returns None if status reporting is disabled."""
59 self.patch(status_listener, "should_start_listener", lambda: False)
60 listener = status_listener.get_listener(None, None)
61 self.assertEqual(listener, None)
62
6357
64def listen_for(event_q, event, callback, count=1, collect=False):58def listen_for(event_q, event, callback, count=1, collect=False):
65 """Setup a EQ listener for the specified event."""59 """Setup a EQ listener for the specified event."""
6660
=== removed directory 'ubuntuone/eventlog'
=== removed file 'ubuntuone/eventlog/__init__.py'
--- ubuntuone/eventlog/__init__.py 2012-04-09 20:07:05 +0000
+++ ubuntuone/eventlog/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,29 +0,0 @@
1# ubuntuone.eventlog - Ubuntu One event logging modules
2#
3# Copyright 2010-2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# In addition, as a special exception, the copyright holders give
18# permission to link the code of portions of this program with the
19# OpenSSL library under certain conditions as described in each
20# individual source file, and distribute linked combinations
21# including the two.
22# You must obey the GNU General Public License in all respects
23# for all of the code used other than OpenSSL. If you modify
24# file(s) with this exception, you may extend this exception to your
25# version of the file(s), but you are not obligated to do so. If you
26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.
29"""Event logging module."""
300
=== removed file 'ubuntuone/eventlog/zg_listener.py'
--- ubuntuone/eventlog/zg_listener.py 2012-04-09 20:07:05 +0000
+++ ubuntuone/eventlog/zg_listener.py 1970-01-01 00:00:00 +0000
@@ -1,556 +0,0 @@
1# ubuntuone.eventlog.zg_listener - listen for SD events, log into ZG
2#
3# Author: Alejandro J. Cura <alecu@canonical.com>
4#
5# Copyright 2010-2012 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19# In addition, as a special exception, the copyright holders give
20# permission to link the code of portions of this program with the
21# OpenSSL library under certain conditions as described in each
22# individual source file, and distribute linked combinations
23# including the two.
24# You must obey the GNU General Public License in all respects
25# for all of the code used other than OpenSSL. If you modify
26# file(s) with this exception, you may extend this exception to your
27# version of the file(s), but you are not obligated to do so. If you
28# do not wish to do so, delete this exception statement from your
29# version. If you delete this exception statement from all source
30# files in the program, then also delete it here.
31"""Event logging from SyncDaemon into Zeitgeist."""
32
33import mimetypes
34
35from os.path import basename
36
37from zeitgeist.datamodel import Event, Interpretation, Manifestation, Subject
38from zeitgeist.mimetypes import get_interpretation_for_mimetype
39
40from ubuntuone.eventlog import zglog
41from ubuntuone.syncdaemon.volume_manager import Share, UDF
42
43ACTOR_UBUNTUONE = "dbus://com.ubuntuone.SyncDaemon.service"
44DIRECTORY_MIMETYPE = "inode/directory"
45DEFAULT_MIME = "application/octet-stream"
46DEFAULT_INTERPRETATION = Interpretation.DOCUMENT
47EVENT_INTERPRETATION_U1_FOLDER_SHARED = "u1://FolderShared"
48EVENT_INTERPRETATION_U1_FOLDER_UNSHARED = "u1://FolderUnshared"
49EVENT_INTERPRETATION_U1_SHARE_ACCEPTED = "u1://ShareAccepted"
50EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED = "u1://ShareUnaccepted"
51EVENT_INTERPRETATION_U1_CONFLICT_RENAME = "u1://ConflictRename"
52EVENT_INTERPRETATION_U1_UDF_CREATED = "u1://UserFolderCreated"
53EVENT_INTERPRETATION_U1_UDF_DELETED = "u1://UserFolderDeleted"
54EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED = "u1://UserFolderSubscribed"
55EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED = "u1://UserFolderUnsubscribed"
56MANIFESTATION_U1_CONTACT_DATA_OBJECT = "u1://ContactDataObject"
57INTERPRETATION_U1_CONTACT = "u1://Contact"
58URI_PROTOCOL_U1 = "ubuntuone:"
59STORAGE_LOCAL = ""
60STORAGE_NETWORK = "net"
61STORAGE_DELETED = "deleted"
62
63
64class ZeitgeistListener(object):
65 """An Event Queue listener that logs into ZG."""
66
67 def __init__(self, fsm, vm):
68 """Initialize this instance."""
69 self.fsm = fsm
70 self.vm = vm
71 self.zg = zglog.ZeitgeistLogger()
72 self.newly_created_server_files = set()
73 self.newly_created_local_files = set()
74
75 def handle_AQ_CREATE_SHARE_OK(self, share_id, marker):
76 """Log the 'directory shared thru the server' event."""
77 share_id = str(share_id)
78 share = self.vm.shared.get(share_id)
79 if not share:
80 share = self.vm.marker_share_map[marker]
81 share_id = share.node_id
82 self.log_folder_shared(share, share_id)
83
84 def handle_AQ_SHARE_INVITATION_SENT(self, marker):
85 """Log the 'directory shared thru http' event."""
86 share = self.vm.marker_share_map[marker]
87 mdo = self.fsm.get_by_mdid(marker)
88 self.log_folder_shared(share, mdo.share_id)
89
90 def log_folder_shared(self, share, share_id):
91 """Log the 'directory shared' event."""
92 fullpath = share.path
93 folder_name = basename(fullpath)
94
95 folder = Subject.new_for_values(
96 uri=URI_PROTOCOL_U1 + str(share.node_id),
97 interpretation=Interpretation.FOLDER,
98 manifestation=Manifestation.REMOTE_DATA_OBJECT,
99 origin="file:///" + fullpath,
100 text=folder_name,
101 mimetype=DIRECTORY_MIMETYPE,
102 storage=STORAGE_NETWORK)
103
104 other_username = share.other_username
105 other_user = Subject.new_for_values(
106 uri="mailto:" + other_username,
107 interpretation=INTERPRETATION_U1_CONTACT,
108 text=other_username,
109 manifestation=MANIFESTATION_U1_CONTACT_DATA_OBJECT)
110
111 event = Event.new_for_values(
112 interpretation=EVENT_INTERPRETATION_U1_FOLDER_SHARED,
113 manifestation=Manifestation.USER_ACTIVITY,
114 actor=ACTOR_UBUNTUONE,
115 subjects=[folder, other_user])
116
117 self.zg.log(event)
118
119 def handle_VM_SHARE_DELETED(self, share):
120 """Log the share deleted event."""
121 folder = Subject.new_for_values(
122 uri=URI_PROTOCOL_U1 + str(share.node_id),
123 interpretation=Interpretation.FOLDER,
124 manifestation=Manifestation.REMOTE_DATA_OBJECT,
125 origin="file:///" + share.path,
126 text=basename(share.path),
127 mimetype=DIRECTORY_MIMETYPE,
128 storage=STORAGE_NETWORK)
129
130 other_username = share.other_username
131 other_user = Subject.new_for_values(
132 uri="mailto:" + other_username,
133 interpretation=INTERPRETATION_U1_CONTACT,
134 text=other_username,
135 manifestation=MANIFESTATION_U1_CONTACT_DATA_OBJECT)
136
137 event = Event.new_for_values(
138 interpretation=EVENT_INTERPRETATION_U1_FOLDER_UNSHARED,
139 manifestation=Manifestation.USER_ACTIVITY,
140 actor=ACTOR_UBUNTUONE,
141 subjects=[folder, other_user])
142
143 self.zg.log(event)
144
145 def handle_VM_SHARE_CREATED(self, share_id):
146 """Log the share accepted event."""
147 share = self.vm.shares[share_id]
148
149 folder = Subject.new_for_values(
150 uri=URI_PROTOCOL_U1 + str(share.node_id),
151 interpretation=Interpretation.FOLDER,
152 manifestation=Manifestation.REMOTE_DATA_OBJECT,
153 origin="file:///" + share.path,
154 text=basename(share.path),
155 mimetype=DIRECTORY_MIMETYPE,
156 storage=STORAGE_NETWORK)
157
158 other_username = share.other_username
159 other_user = Subject.new_for_values(
160 uri="mailto:" + other_username,
161 interpretation=INTERPRETATION_U1_CONTACT,
162 text=other_username,
163 manifestation=MANIFESTATION_U1_CONTACT_DATA_OBJECT)
164
165 event = Event.new_for_values(
166 interpretation=EVENT_INTERPRETATION_U1_SHARE_ACCEPTED,
167 manifestation=Manifestation.USER_ACTIVITY,
168 actor=ACTOR_UBUNTUONE,
169 subjects=[folder, other_user])
170
171 self.zg.log(event)
172
173 def log_share_unaccepted(self, share):
174 """Log the share unaccepted event."""
175 folder = Subject.new_for_values(
176 uri=URI_PROTOCOL_U1 + str(share.node_id),
177 interpretation=Interpretation.FOLDER,
178 manifestation=Manifestation.REMOTE_DATA_OBJECT,
179 origin="file:///" + share.path,
180 text=basename(share.path),
181 mimetype=DIRECTORY_MIMETYPE,
182 storage=STORAGE_NETWORK)
183
184 other_username = share.other_username
185 other_user = Subject.new_for_values(
186 uri="mailto:" + other_username,
187 interpretation=INTERPRETATION_U1_CONTACT,
188 text=other_username,
189 manifestation=MANIFESTATION_U1_CONTACT_DATA_OBJECT)
190
191 event = Event.new_for_values(
192 interpretation=EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED,
193 manifestation=Manifestation.USER_ACTIVITY,
194 actor=ACTOR_UBUNTUONE,
195 subjects=[folder, other_user])
196
197 self.zg.log(event)
198
199 def log_udf_deleted(self, volume):
200 """Log the udf deleted event."""
201 folder = Subject.new_for_values(
202 uri=URI_PROTOCOL_U1 + str(volume.node_id),
203 interpretation=Interpretation.FOLDER,
204 manifestation=Manifestation.DELETED_RESOURCE,
205 origin="file:///" + volume.path,
206 text=basename(volume.path),
207 mimetype=DIRECTORY_MIMETYPE,
208 storage=STORAGE_DELETED)
209
210 event = Event.new_for_values(
211 interpretation=EVENT_INTERPRETATION_U1_UDF_DELETED,
212 manifestation=Manifestation.USER_ACTIVITY,
213 actor=ACTOR_UBUNTUONE,
214 subjects=[folder])
215
216 self.zg.log(event)
217
218 def handle_VM_VOLUME_DELETED(self, volume):
219 """Log the share/UDF unaccepted event."""
220 if isinstance(volume, Share):
221 self.log_share_unaccepted(volume)
222 if isinstance(volume, UDF):
223 self.log_udf_deleted(volume)
224
225 def handle_VM_UDF_CREATED(self, udf):
226 """An udf was created. Log it into Zeitgeist."""
227 folder = Subject.new_for_values(
228 uri=URI_PROTOCOL_U1 + str(udf.node_id),
229 interpretation=Interpretation.FOLDER,
230 manifestation=Manifestation.REMOTE_DATA_OBJECT,
231 origin="file:///" + udf.path,
232 text=basename(udf.path),
233 mimetype=DIRECTORY_MIMETYPE,
234 storage=STORAGE_NETWORK)
235
236 event = Event.new_for_values(
237 interpretation=EVENT_INTERPRETATION_U1_UDF_CREATED,
238 manifestation=Manifestation.USER_ACTIVITY,
239 actor=ACTOR_UBUNTUONE,
240 subjects=[folder])
241
242 self.zg.log(event)
243
244 def handle_VM_UDF_SUBSCRIBED(self, udf):
245 """An udf was subscribed."""
246
247 folder = Subject.new_for_values(
248 uri="file:///" + udf.path,
249 interpretation=Interpretation.FOLDER,
250 manifestation=Manifestation.FILE_DATA_OBJECT,
251 origin=URI_PROTOCOL_U1 + str(udf.node_id),
252 text=basename(udf.path),
253 mimetype=DIRECTORY_MIMETYPE,
254 storage=STORAGE_LOCAL)
255
256 event = Event.new_for_values(
257 interpretation=EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED,
258 manifestation=Manifestation.USER_ACTIVITY,
259 actor=ACTOR_UBUNTUONE,
260 subjects=[folder])
261
262 self.zg.log(event)
263
264 def handle_VM_UDF_UNSUBSCRIBED(self, udf):
265 """An udf was unsubscribed."""
266
267 folder = Subject.new_for_values(
268 uri="file:///" + udf.path,
269 interpretation=Interpretation.FOLDER,
270 manifestation=Manifestation.DELETED_RESOURCE,
271 origin=URI_PROTOCOL_U1 + str(udf.node_id),
272 text=basename(udf.path),
273 mimetype=DIRECTORY_MIMETYPE,
274 storage=STORAGE_DELETED)
275
276 event = Event.new_for_values(
277 interpretation=EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED,
278 manifestation=Manifestation.USER_ACTIVITY,
279 actor=ACTOR_UBUNTUONE,
280 subjects=[folder])
281
282 self.zg.log(event)
283
284 def handle_AQ_FILE_NEW_OK(self, volume_id, marker, new_id, new_generation):
285 """A new file was created on server. Store and wait till it uploads."""
286 self.newly_created_server_files.add((volume_id, new_id))
287
288 def get_mime_and_interpretation_for_filepath(self, filepath):
289 """Try to guess the mime and the interpretation from the path."""
290 mime, encoding = mimetypes.guess_type(filepath)
291 if mime is None:
292 return DEFAULT_MIME, DEFAULT_INTERPRETATION
293 interpret = get_interpretation_for_mimetype(mime)
294 if interpret is None:
295 return DEFAULT_MIME, Interpretation.DOCUMENT
296 return mime, interpret
297
298 def handle_AQ_UPLOAD_FINISHED(self, share_id, node_id, hash,
299 new_generation):
300 """A file finished uploading to the server."""
301
302 mdo = self.fsm.get_by_node_id(share_id, node_id)
303 path = self.fsm.get_abspath(share_id, mdo.path)
304
305 if (share_id, node_id) in self.newly_created_server_files:
306 self.newly_created_server_files.remove((share_id, node_id))
307 event_interpretation = Interpretation.CREATE_EVENT
308 else:
309 event_interpretation = Interpretation.MODIFY_EVENT
310
311 mime, interp = self.get_mime_and_interpretation_for_filepath(path)
312
313 file_subject = Subject.new_for_values(
314 uri=URI_PROTOCOL_U1 + str(node_id),
315 interpretation=interp,
316 manifestation=Manifestation.REMOTE_DATA_OBJECT,
317 origin="file:///" + path,
318 text=basename(path),
319 mimetype=mime,
320 storage=STORAGE_NETWORK)
321
322 event = Event.new_for_values(
323 interpretation=event_interpretation,
324 manifestation=Manifestation.SCHEDULED_ACTIVITY,
325 actor=ACTOR_UBUNTUONE,
326 subjects=[file_subject])
327
328 self.zg.log(event)
329
330 def handle_AQ_DIR_NEW_OK(self, volume_id, marker, new_id, new_generation):
331 """A dir was created on the server."""
332
333 mdo = self.fsm.get_by_node_id(volume_id, new_id)
334 path = self.fsm.get_abspath(volume_id, mdo.path)
335
336 file_subject = Subject.new_for_values(
337 uri=URI_PROTOCOL_U1 + str(new_id),
338 interpretation=Interpretation.FOLDER,
339 manifestation=Manifestation.REMOTE_DATA_OBJECT,
340 origin="file:///" + path,
341 text=basename(path),
342 mimetype=DIRECTORY_MIMETYPE,
343 storage=STORAGE_NETWORK)
344
345 event = Event.new_for_values(
346 interpretation=Interpretation.CREATE_EVENT,
347 manifestation=Manifestation.SCHEDULED_ACTIVITY,
348 actor=ACTOR_UBUNTUONE,
349 subjects=[file_subject])
350
351 self.zg.log(event)
352
353 def handle_SV_FILE_NEW(self, volume_id, node_id, parent_id, name):
354 """A file was created locally by Syncdaemon."""
355 self.newly_created_local_files.add((volume_id, node_id))
356
357 def handle_AQ_DOWNLOAD_FINISHED(self, share_id, node_id, server_hash):
358 """A file finished downloading from the server."""
359
360 mdo = self.fsm.get_by_node_id(share_id, node_id)
361 path = self.fsm.get_abspath(share_id, mdo.path)
362
363 if (share_id, node_id) in self.newly_created_local_files:
364 self.newly_created_local_files.remove((share_id, node_id))
365 event_interpretation = Interpretation.CREATE_EVENT
366 else:
367 event_interpretation = Interpretation.MODIFY_EVENT
368
369 mime, interp = self.get_mime_and_interpretation_for_filepath(path)
370
371 file_subject = Subject.new_for_values(
372 uri="file:///" + path,
373 interpretation=interp,
374 manifestation=Manifestation.FILE_DATA_OBJECT,
375 origin=URI_PROTOCOL_U1 + str(node_id),
376 text=basename(path),
377 mimetype=mime,
378 storage=STORAGE_LOCAL)
379
380 event = Event.new_for_values(
381 interpretation=event_interpretation,
382 manifestation=Manifestation.WORLD_ACTIVITY,
383 actor=ACTOR_UBUNTUONE,
384 subjects=[file_subject])
385
386 self.zg.log(event)
387
388 def handle_SV_DIR_NEW(self, volume_id, node_id, parent_id, name):
389 """A file finished downloading from the server."""
390
391 mdo = self.fsm.get_by_node_id(volume_id, node_id)
392 path = self.fsm.get_abspath(volume_id, mdo.path)
393
394 file_subject = Subject.new_for_values(
395 uri="file:///" + path,
396 interpretation=Interpretation.FOLDER,
397 manifestation=Manifestation.FILE_DATA_OBJECT,
398 origin=URI_PROTOCOL_U1 + str(node_id),
399 text=basename(path),
400 mimetype=DIRECTORY_MIMETYPE,
401 storage=STORAGE_LOCAL)
402
403 event = Event.new_for_values(
404 interpretation=Interpretation.CREATE_EVENT,
405 manifestation=Manifestation.WORLD_ACTIVITY,
406 actor=ACTOR_UBUNTUONE,
407 subjects=[file_subject])
408
409 self.zg.log(event)
410
411 def handle_SV_FILE_DELETED(self, volume_id, node_id, was_dir, old_path):
412 """A file or folder was deleted locally by Syncdaemon."""
413 if was_dir:
414 mime, interp = DIRECTORY_MIMETYPE, Interpretation.FOLDER
415 else:
416 mime, interp = self.get_mime_and_interpretation_for_filepath(
417 old_path)
418
419 file_subject = Subject.new_for_values(
420 uri="file:///" + old_path,
421 interpretation=interp,
422 manifestation=Manifestation.DELETED_RESOURCE,
423 origin=URI_PROTOCOL_U1 + str(node_id),
424 text=basename(old_path),
425 mimetype=mime,
426 storage=STORAGE_DELETED)
427
428 event = Event.new_for_values(
429 interpretation=Interpretation.DELETE_EVENT,
430 manifestation=Manifestation.WORLD_ACTIVITY,
431 actor=ACTOR_UBUNTUONE,
432 subjects=[file_subject])
433
434 self.zg.log(event)
435
436 def handle_AQ_UNLINK_OK(self, share_id, parent_id, node_id,
437 new_generation, was_dir, old_path):
438 """A file or folder was deleted on the server by Syncdaemon,"""
439 if was_dir:
440 mime, interp = DIRECTORY_MIMETYPE, Interpretation.FOLDER
441 else:
442 mime, interp = self.get_mime_and_interpretation_for_filepath(
443 old_path)
444
445 file_subject = Subject.new_for_values(
446 uri=URI_PROTOCOL_U1 + str(node_id),
447 interpretation=interp,
448 manifestation=Manifestation.DELETED_RESOURCE,
449 origin="file:///" + old_path,
450 text=basename(old_path),
451 mimetype=mime,
452 storage=STORAGE_DELETED)
453
454 event = Event.new_for_values(
455 interpretation=Interpretation.DELETE_EVENT,
456 manifestation=Manifestation.SCHEDULED_ACTIVITY,
457 actor=ACTOR_UBUNTUONE,
458 subjects=[file_subject])
459
460 self.zg.log(event)
461
462 def handle_FSM_FILE_CONFLICT(self, old_name, new_name):
463 """A file was renamed because of conflict."""
464 mime, interp = self.get_mime_and_interpretation_for_filepath(old_name)
465
466 file_subject = Subject.new_for_values(
467 uri="file:///" + new_name,
468 interpretation=interp,
469 manifestation=Manifestation.FILE_DATA_OBJECT,
470 origin="file:///" + old_name,
471 text=basename(new_name),
472 mimetype=mime,
473 storage=STORAGE_LOCAL)
474
475 event = Event.new_for_values(
476 interpretation=EVENT_INTERPRETATION_U1_CONFLICT_RENAME,
477 manifestation=Manifestation.WORLD_ACTIVITY,
478 actor=ACTOR_UBUNTUONE,
479 subjects=[file_subject])
480
481 self.zg.log(event)
482
483 def handle_FSM_DIR_CONFLICT(self, old_name, new_name):
484 """A dir was renamed because of conflict."""
485 folder_subject = Subject.new_for_values(
486 uri="file:///" + new_name,
487 interpretation=Interpretation.FOLDER,
488 manifestation=Manifestation.FILE_DATA_OBJECT,
489 origin="file:///" + old_name,
490 text=basename(new_name),
491 mimetype=DIRECTORY_MIMETYPE,
492 storage=STORAGE_LOCAL)
493
494 event = Event.new_for_values(
495 interpretation=EVENT_INTERPRETATION_U1_CONFLICT_RENAME,
496 manifestation=Manifestation.WORLD_ACTIVITY,
497 actor=ACTOR_UBUNTUONE,
498 subjects=[folder_subject])
499
500 self.zg.log(event)
501
502 def handle_AQ_CHANGE_PUBLIC_ACCESS_OK(self, share_id, node_id, is_public,
503 public_url):
504 """The status of a published resource changed. Log it!"""
505 if is_public:
506 self.log_publishing(share_id, node_id, is_public, public_url)
507 else:
508 self.log_unpublishing(share_id, node_id, is_public, public_url)
509
510 def log_publishing(self, share_id, node_id, is_public, public_url):
511 """Log the publishing of a resource."""
512 mime, interp = self.get_mime_and_interpretation_for_filepath(
513 public_url)
514
515 origin = "" if node_id is None else URI_PROTOCOL_U1 + str(node_id)
516
517 public_file = Subject.new_for_values(
518 uri=public_url,
519 interpretation=interp,
520 manifestation=Manifestation.REMOTE_DATA_OBJECT,
521 origin=origin,
522 text=public_url,
523 mimetype=mime,
524 storage=STORAGE_NETWORK)
525
526 event = Event.new_for_values(
527 interpretation=Interpretation.CREATE_EVENT,
528 manifestation=Manifestation.USER_ACTIVITY,
529 actor=ACTOR_UBUNTUONE,
530 subjects=[public_file])
531
532 self.zg.log(event)
533
534 def log_unpublishing(self, share_id, node_id, is_public, public_url):
535 """Log the unpublishing of a resource."""
536 mime, interp = self.get_mime_and_interpretation_for_filepath(
537 public_url)
538
539 origin = "" if node_id is None else URI_PROTOCOL_U1 + str(node_id)
540
541 public_file = Subject.new_for_values(
542 uri=public_url,
543 interpretation=interp,
544 manifestation=Manifestation.DELETED_RESOURCE,
545 text=public_url,
546 origin=origin,
547 mimetype=mime,
548 storage=STORAGE_DELETED)
549
550 event = Event.new_for_values(
551 interpretation=Interpretation.DELETE_EVENT,
552 manifestation=Manifestation.USER_ACTIVITY,
553 actor=ACTOR_UBUNTUONE,
554 subjects=[public_file])
555
556 self.zg.log(event)
5570
=== removed file 'ubuntuone/eventlog/zglog.py'
--- ubuntuone/eventlog/zglog.py 2012-04-09 20:07:05 +0000
+++ ubuntuone/eventlog/zglog.py 1970-01-01 00:00:00 +0000
@@ -1,61 +0,0 @@
1# -*- coding: utf-8 -*-
2#
3# Author: Alejandro J. Cura <alecu@canonical.com>
4#
5# Copyright 2010-2012 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19# In addition, as a special exception, the copyright holders give
20# permission to link the code of portions of this program with the
21# OpenSSL library under certain conditions as described in each
22# individual source file, and distribute linked combinations
23# including the two.
24# You must obey the GNU General Public License in all respects
25# for all of the code used other than OpenSSL. If you modify
26# file(s) with this exception, you may extend this exception to your
27# version of the file(s), but you are not obligated to do so. If you
28# do not wish to do so, delete this exception statement from your
29# version. If you delete this exception statement from all source
30# files in the program, then also delete it here.
31"""Log into the Zeitgeist daemon."""
32
33from twisted.internet.defer import Deferred
34
35from ubuntuone.logger import logging
36
37logger = logging.getLogger('ubuntuone.eventlog.zglog')
38
39
40class ZeitgeistLogger(object):
41 """A class that logs zeitgeist events."""
42 client = None
43
44 def __init__(self):
45 """Initialize this instance."""
46 try:
47 from zeitgeist.client import ZeitgeistClient
48 self.client = ZeitgeistClient()
49 logger.info("Zeitgeist support initialized.")
50 except Exception:
51 logger.exception("Zeitgeist support not started:")
52
53 def log(self, event):
54 """Log a zeitgeist event."""
55 d = Deferred()
56 if self.client:
57 logger.info("Logging Zeitgeist event: %r", event)
58 self.client.insert_event(event, d.callback, d.errback)
59 else:
60 d.callback([])
61 return d
620
=== removed directory 'ubuntuone/platform/event_logging'
=== removed file 'ubuntuone/platform/event_logging/__init__.py'
--- ubuntuone/platform/event_logging/__init__.py 2012-05-01 17:43:39 +0000
+++ ubuntuone/platform/event_logging/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,39 +0,0 @@
1# -*- coding: utf-8 *-*
2#
3# Copyright 2011-2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# In addition, as a special exception, the copyright holders give
18# permission to link the code of portions of this program with the
19# OpenSSL library under certain conditions as described in each
20# individual source file, and distribute linked combinations
21# including the two.
22# You must obey the GNU General Public License in all respects
23# for all of the code used other than OpenSSL. If you modify
24# file(s) with this exception, you may extend this exception to your
25# version of the file(s), but you are not obligated to do so. If you
26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.
29"""Builds a syncdaemon listener that logs events if ZG is installed."""
30
31import sys
32
33if sys.platform in ["win32", "darwin"]:
34 # Zeitgeist is not installed on these platforms
35 get_listener = lambda x, y: None
36else:
37 from ubuntuone.platform.event_logging import linux as source
38 get_listener = source.get_listener
39
400
=== removed file 'ubuntuone/platform/event_logging/linux.py'
--- ubuntuone/platform/event_logging/linux.py 2012-04-27 22:55:12 +0000
+++ ubuntuone/platform/event_logging/linux.py 1970-01-01 00:00:00 +0000
@@ -1,51 +0,0 @@
1#
2# Author: Alejandro J. Cura <alecu@canonical.com>
3#
4# Copyright 2010-2012 Canonical Ltd.
5#
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17#
18# In addition, as a special exception, the copyright holders give
19# permission to link the code of portions of this program with the
20# OpenSSL library under certain conditions as described in each
21# individual source file, and distribute linked combinations
22# including the two.
23# You must obey the GNU General Public License in all respects
24# for all of the code used other than OpenSSL. If you modify
25# file(s) with this exception, you may extend this exception to your
26# version of the file(s), but you are not obligated to do so. If you
27# do not wish to do so, delete this exception statement from your
28# version. If you delete this exception statement from all source
29# files in the program, then also delete it here.
30"""Builds a syncdaemon listener that logs events if ZG is installed."""
31
32
33def is_zeitgeist_installed():
34 """Return true if zeitgeist is installed."""
35 try:
36 import zeitgeist
37 import zeitgeist.mimetypes
38 # use the above module in some way so pylint does not complain
39 assert(zeitgeist is not None)
40 return True
41 except (ImportError, AttributeError):
42 return False
43
44
45def get_listener(fsm, vm):
46 """Build a listener if zg is installed."""
47 if is_zeitgeist_installed():
48 from ubuntuone.eventlog import zg_listener
49 return zg_listener.ZeitgeistListener(fsm, vm)
50 else:
51 return None
520
=== modified file 'ubuntuone/syncdaemon/main.py'
--- ubuntuone/syncdaemon/main.py 2013-01-22 20:03:12 +0000
+++ ubuntuone/syncdaemon/main.py 2013-02-04 16:10:53 +0000
@@ -48,7 +48,6 @@
48 volume_manager,48 volume_manager,
49)49)
50from ubuntuone import syncdaemon, clientdefs50from ubuntuone import syncdaemon, clientdefs
51from ubuntuone.platform import event_logging
52from ubuntuone.syncdaemon import status_listener51from ubuntuone.syncdaemon import status_listener
53from ubuntuone.syncdaemon.interaction_interfaces import SyncdaemonService52from ubuntuone.syncdaemon.interaction_interfaces import SyncdaemonService
54from ubuntuone.syncdaemon.states import StateManager, QueueManager53from ubuntuone.syncdaemon.states import StateManager, QueueManager
@@ -147,22 +146,12 @@
147 if user_config.get_autoconnect():146 if user_config.get_autoconnect():
148 self.external.connect(autoconnecting=True)147 self.external.connect(autoconnecting=True)
149148
150 self.eventlog_listener = None
151 self.start_event_logger()
152
153 self.status_listener = None149 self.status_listener = None
154 self.start_status_listener()150 self.start_status_listener()
155151
156 self.mark = task.LoopingCall(self.log_mark)152 self.mark = task.LoopingCall(self.log_mark)
157 self.mark.start(mark_interval)153 self.mark.start(mark_interval)
158154
159 def start_event_logger(self):
160 """Start the event logger if it's available for this platform."""
161 self.eventlog_listener = event_logging.get_listener(self.fs, self.vm)
162 # subscribe to EQ, to be unsubscribed in shutdown
163 if self.eventlog_listener:
164 self.event_q.subscribe(self.eventlog_listener)
165
166 def start_status_listener(self):155 def start_status_listener(self):
167 """Start the status listener if it is configured to start."""156 """Start the status listener if it is configured to start."""
168 self.status_listener = status_listener.get_listener(self.fs, self.vm,157 self.status_listener = status_listener.get_listener(self.fs, self.vm,
@@ -228,8 +217,6 @@
228 self.event_q.push('SYS_QUIT')217 self.event_q.push('SYS_QUIT')
229218
230 self.event_q.unsubscribe(self.vm)219 self.event_q.unsubscribe(self.vm)
231 if getattr(self, 'eventlog_listener', None) is not None:
232 self.event_q.unsubscribe(self.eventlog_listener)
233 if getattr(self, 'status_listener', None) is not None:220 if getattr(self, 'status_listener', None) is not None:
234 self.event_q.unsubscribe(self.status_listener)221 self.event_q.unsubscribe(self.status_listener)
235222

Subscribers

People subscribed via source and target branches