diff -Nru ubuntuone-client-3.0.0/configure ubuntuone-client-3.0.2/configure --- ubuntuone-client-3.0.0/configure 2012-04-11 15:10:51.000000000 +0000 +++ ubuntuone-client-3.0.2/configure 2012-06-14 20:48:16.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for ubuntuone-client 3.0.0. +# Generated by GNU Autoconf 2.68 for ubuntuone-client 3.0.2. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -627,8 +627,8 @@ # Identity of this package. PACKAGE_NAME='ubuntuone-client' PACKAGE_TARNAME='ubuntuone-client' -PACKAGE_VERSION='3.0.0' -PACKAGE_STRING='ubuntuone-client 3.0.0' +PACKAGE_VERSION='3.0.2' +PACKAGE_STRING='ubuntuone-client 3.0.2' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1468,7 +1468,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures ubuntuone-client 3.0.0 to adapt to many kinds of systems. +\`configure' configures ubuntuone-client 3.0.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1539,7 +1539,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of ubuntuone-client 3.0.0:";; + short | recursive ) echo "Configuration of ubuntuone-client 3.0.2:";; esac cat <<\_ACEOF @@ -1668,7 +1668,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -ubuntuone-client configure 3.0.0 +ubuntuone-client configure 3.0.2 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -1946,7 +1946,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by ubuntuone-client $as_me 3.0.0, which was +It was created by ubuntuone-client $as_me 3.0.2, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2763,7 +2763,7 @@ # Define the identity of the package. PACKAGE='ubuntuone-client' - VERSION='3.0.0' + VERSION='3.0.2' cat >>confdefs.h <<_ACEOF @@ -14628,7 +14628,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by ubuntuone-client $as_me 3.0.0, which was +This file was extended by ubuntuone-client $as_me 3.0.2, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14694,7 +14694,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -ubuntuone-client config.status 3.0.0 +ubuntuone-client config.status 3.0.2 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" diff -Nru ubuntuone-client-3.0.0/configure.ac ubuntuone-client-3.0.2/configure.ac --- ubuntuone-client-3.0.0/configure.ac 2012-04-11 15:09:58.000000000 +0000 +++ ubuntuone-client-3.0.2/configure.ac 2012-06-14 20:17:22.000000000 +0000 @@ -1,7 +1,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.53) -AC_INIT([ubuntuone-client], [3.0.0]) +AC_INIT([ubuntuone-client], [3.0.2]) AC_CONFIG_SRCDIR([config.h.in]) AM_INIT_AUTOMAKE([1.10 foreign]) Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/contrib/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/contrib/__init__.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/contrib/testing/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/contrib/testing/__init__.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/contrib/testing/testcase.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/contrib/testing/testcase.pyc differ diff -Nru ubuntuone-client-3.0.0/data/syncdaemon.conf ubuntuone-client-3.0.2/data/syncdaemon.conf --- ubuntuone-client-3.0.0/data/syncdaemon.conf 2012-03-07 14:43:51.000000000 +0000 +++ ubuntuone-client-3.0.2/data/syncdaemon.conf 2012-06-14 20:17:10.000000000 +0000 @@ -2,7 +2,7 @@ host.default = fs-1.one.ubuntu.com host.help = The server address -dns_srv.default = _https._tcp.fs.ubuntuone.com +dns_srv.default = _https._tcp.fs.one.ubuntu.com dns_srv.help = The DNS SRV record disable_ssl_verify.default = False @@ -84,6 +84,7 @@ \A.*\.swpx\Z \A\..*\.tmp\Z \A\.~lock\..*#\Z + \A\.goutputstream-.*\Z use_trash.default = True use_trash.parser = bool diff -Nru ubuntuone-client-3.0.0/debian/changelog ubuntuone-client-3.0.2/debian/changelog --- ubuntuone-client-3.0.0/debian/changelog 2012-05-29 18:11:50.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/changelog 2014-05-23 01:27:13.000000000 +0000 @@ -1,3 +1,52 @@ +ubuntuone-client (3.0.2-0ubuntu2.2) precise-proposed; urgency=medium + + * debian/patches/00_farewell-u1.patch: + - Pop up a notice when connecting the service will stop on June 1 2014. + - Avoid trying to connect after June 1 2014. (LP: #1306225) + + -- Rodney Dawes Thu, 22 May 2014 21:26:57 -0400 + +ubuntuone-client (3.0.2-0ubuntu2) precise-proposed; urgency=low + + * debian/control: + * debian/python-ubuntuone-client.install: + * debian/patches/01_bzr1384_remove_zg.patch, + debian/patches/02_bzr-ensure-content-type.patch: + - Backport removal of zeitgeist usage, + - Set the Content-Type header for the POST request. + - Set public_url to '' when it is None. (LP: #1193274) + + -- Rodney Dawes Fri, 30 Aug 2013 16:46:51 -0400 + +ubuntuone-client (3.0.2-0ubuntu1) precise-proposed; urgency=low + + * New upstream release. (LP: #1018991) + - Wrap empty dicts with dbus.Dictionary. (LP: #711162) + - Ignore IN_CLOSE_WRITE for directories. (LP: #872894) + - Ignore .goutputstream temporary flies. (LP: #1012620) + - Handle failures better in share creation. (LP: #1013180) + * debian/copyright: + - Remove comma in list of files for dep5 copyright format. + * 00_bzr1259_lp1013401_reupload.patch: + - Re-upload files when server reports empty hash. (LP: #1013401) + * debian/patches: + - Remove upstreamed patches. + + -- Rodney Dawes Mon, 09 Jul 2012 15:46:44 -0400 + +ubuntuone-client (3.0.1-0ubuntu1.0.1) precise-proposed; urgency=low + + * New upstream release. + - Don't ignore test failures in from main tests suite. (LP: #993574) + - Avoid multiple parallel GetDelta commands on same volume. (LP: #883252) + - Fix small memory leak in folder enabled check. (LP: #981255) + - Don't start syncdaemon with u1sdtool -q if not running. (LP: #907479) + - Avoid having Upload execute before Makefile command. (LP: #978903) + * debian/watch: + - Update watch file to use stable-3-0 series for downloads now + + -- Rodney Dawes Wed, 06 Jun 2012 14:08:37 -0400 + ubuntuone-client (3.0.0-0ubuntu1.1) precise-security; urgency=low * SECURITY UPDATE: MITM via incorrect ssl cert validation (LP: #882062) diff -Nru ubuntuone-client-3.0.0/debian/control ubuntuone-client-3.0.2/debian/control --- ubuntuone-client-3.0.0/debian/control 2012-05-29 18:10:25.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/control 2014-04-10 21:13:53.000000000 +0000 @@ -73,7 +73,6 @@ python-oauth (>= 1.0~svn1092-0ubuntu2) Provides: ${python:Provides} Replaces: ubuntuone-client (<< 0.92.0-0ubuntu1) -Recommends: zeitgeist-core Description: Ubuntu One client Python libraries Ubuntu One is a suite of on-line services. This package provides the Python libraries for the Ubuntu One file storage and sharing synchronization diff -Nru ubuntuone-client-3.0.0/debian/copyright ubuntuone-client-3.0.2/debian/copyright --- ubuntuone-client-3.0.0/debian/copyright 2012-04-11 19:21:42.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/copyright 2014-04-10 21:13:53.000000000 +0000 @@ -31,7 +31,7 @@ version. If you delete this exception statement from all source files in the program, then also delete it here. -Files: *.svg, ./data/icons/* +Files: *.svg ./data/icons/* Copyright: 2009-2012 Canonical Ltd. License: CC-BY-SA-3.0 Creative Commons Attribution-ShareAlike 3.0 diff -Nru ubuntuone-client-3.0.0/debian/patches/00_bzr1259_lp1013401_reupload.patch ubuntuone-client-3.0.2/debian/patches/00_bzr1259_lp1013401_reupload.patch --- ubuntuone-client-3.0.0/debian/patches/00_bzr1259_lp1013401_reupload.patch 1970-01-01 00:00:00.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/patches/00_bzr1259_lp1013401_reupload.patch 2014-04-10 21:13:53.000000000 +0000 @@ -0,0 +1,79 @@ +=== modified file 'tests/syncdaemon/test_sync.py' +--- old/tests/syncdaemon/test_sync.py 2012-04-23 14:41:17 +0000 ++++ new/tests/syncdaemon/test_sync.py 2012-06-13 21:31:24 +0000 +@@ -387,20 +387,29 @@ class TestSync(BaseSync): + self.sync._handle_SV_HASH_NEW(mdobj.share_id, mdobj.node_id, '') + self.assertTrue(self.called) + +- def test_SV_HASH_NEW_with_file_uploadinterrupted_coverage(self): +- """A SV_HASH_NEW is received after upload interrupted.""" ++ def test_SV_HASH_NEW_with_special_hash(self): ++ """A SV_HASH_NEW is received with hash in None, don't care state.""" + self.called = False + +- # create a file and put it in local, without server_hash, as +- # if the upload was cut in the middle after the make file ++ def fake_meth(_, event, params, hash): ++ """Wrap SSMR.reput_file_from_local to test.""" ++ self.assertEqual(event, 'SV_HASH_NEW') ++ self.assertEqual(hash, '') ++ self.called = True ++ self.patch(SyncStateMachineRunner, 'reput_file_from_local', fake_meth) ++ ++ # create a file and leave it as NONE state + somepath = os.path.join(self.root, 'somepath') + mdid = self.fsm.create(somepath, '', node_id='node_id') +- self.fsm.set_by_mdid(mdid, local_hash='somehash', crc32='crc32', +- stat='stat', size='size') ++ self.fsm.set_by_mdid(mdid, local_hash='somehsh', server_hash='somehsh', ++ crc32='crc32', stat='stat', size='size') + + # send the event with no content and check + mdobj = self.fsm.get_by_mdid(mdid) + self.sync._handle_SV_HASH_NEW(mdobj.share_id, mdobj.node_id, '') ++ self.assertTrue(self.called) ++ mdobj = self.fsm.get_by_mdid(mdid) ++ self.assertEqual(mdobj.server_hash, '') + + def test_AQ_FILE_NEW_OK_with_md_in_none(self): + """Created the file, and MD says it's in NONE.""" +@@ -991,7 +1000,6 @@ class SyncStateMachineRunnerTestCase(Bas + with self._test_putcontent_upload_id(with_upload_id=False): + self.ssmr.reput_file_from_local("SV_HASH_NEW", None, '') + +- + def test_commit_file_without_partial(self): + """The .partial is lost when commiting the file.""" + # create the partial correctly, and break it! + +=== modified file 'ubuntuone/syncdaemon/sync.py' +--- old/ubuntuone/syncdaemon/sync.py 2012-04-09 20:08:42 +0000 ++++ new/ubuntuone/syncdaemon/sync.py 2012-06-13 21:31:24 +0000 +@@ -589,10 +589,10 @@ class SyncStateMachineRunner(StateMachin + """Starts the scan again on a dir.""" + self.m.lr.scan_dir(self.key['mdid'], self.key['path'], udfmode) + +- def reput_file_from_local(self, event, params, hash): ++ def reput_file_from_local(self, event, params, hash_value): + """Re put the file from its local state.""" + self.m.action_q.cancel_upload(share_id=self.key['share_id'], +- node_id=self.key['node_id']) ++ node_id=self.key['node_id']) + + local_hash = self.key['local_hash'] + previous_hash = self.key['server_hash'] +@@ -841,7 +841,13 @@ class Sync(object): + """on SV_HASH_NEW. No longer called by EQ, only internally.""" + key = FSKey(self.m.fs, share_id=share_id, node_id=node_id) + log = FileLogger(self.logger, key) ++ + ssmr = SyncStateMachineRunner(self.fsm, self.m, key, log) ++ if hash == "": ++ # Special case for hash == "", aka broken node. ++ # Set the server_hash = hash to force LOCAL state ++ key.set(server_hash=hash) ++ key.sync() + ssmr.signal_event_with_hash("SV_HASH_NEW", hash) + + def _handle_SV_FILE_NEW(self, share_id, node_id, parent_id, name): + diff -Nru ubuntuone-client-3.0.0/debian/patches/00_farewell-u1.patch ubuntuone-client-3.0.2/debian/patches/00_farewell-u1.patch --- ubuntuone-client-3.0.0/debian/patches/00_farewell-u1.patch 1970-01-01 00:00:00.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/patches/00_farewell-u1.patch 2014-05-22 19:34:56.000000000 +0000 @@ -0,0 +1,50 @@ +=== modified file 'ubuntuone/status/aggregator.py' +--- old/ubuntuone/status/aggregator.py 2012-04-09 20:07:05 +0000 ++++ new/ubuntuone/status/aggregator.py 2014-05-22 19:30:52 +0000 +@@ -49,6 +49,8 @@ ONE_DAY = 24 * 60 * 60 + Q_ = lambda string: gettext.dgettext(GETTEXT_PACKAGE, string) + + UBUNTUONE_TITLE = Q_("Ubuntu One") ++UBUNTUONE_END = Q_("Ubuntu One file services will be " ++ "shutting down on June 1st, 2014.\nThanks for your support.") + NEW_UDFS_SENDER = Q_("New cloud folder(s) available") + FINAL_COMPLETED = Q_("File synchronization completed.") + +@@ -805,6 +807,12 @@ class StatusFrontend(object): + self.notification = self.aggregator.get_notification() + self.messaging = Messaging() + self.quota_timer = None ++ self.farewell_ubuntuone_sync() ++ ++ def farewell_ubuntuone_sync(self): ++ """Show notification about the upcoming end of UbuntuOne sync.""" ++ self.notification.send_notification( ++ UBUNTUONE_TITLE, UBUNTUONE_END) + + def file_published(self, public_url): + """A file was published.""" + +=== modified file 'ubuntuone/syncdaemon/interaction_interfaces.py' +--- old/ubuntuone/syncdaemon/interaction_interfaces.py 2012-04-09 20:07:05 +0000 ++++ new/ubuntuone/syncdaemon/interaction_interfaces.py 2014-05-22 19:33:19 +0000 +@@ -38,6 +38,7 @@ unicode, so ID's and paths will be encod + """ + + import collections ++import datetime + import logging + import os + import uuid +@@ -1231,6 +1232,11 @@ class SyncdaemonService(SyncdaemonObject + for login/registration, only already existent credentials will be used. + + """ ++ # Avoid connecting after June 1 ++ end_date = datetime.date(2014, 6, 1) ++ if datetime.date.today() >= end_date: ++ return ++ + if self.oauth_credentials is not None: + logger.debug('connect: oauth credentials were given by parameter.') + ckey = csecret = key = secret = None + diff -Nru ubuntuone-client-3.0.0/debian/patches/01_bzr1384_remove_zg.patch ubuntuone-client-3.0.2/debian/patches/01_bzr1384_remove_zg.patch --- ubuntuone-client-3.0.0/debian/patches/01_bzr1384_remove_zg.patch 1970-01-01 00:00:00.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/patches/01_bzr1384_remove_zg.patch 2014-04-10 21:13:53.000000000 +0000 @@ -0,0 +1,2447 @@ +=== modified file 'contrib/testing/testcase.py' +--- old/contrib/testing/testcase.py 2012-04-09 20:07:05 +0000 ++++ new/contrib/testing/testcase.py 2013-08-27 16:33:16 +0000 +@@ -241,7 +241,6 @@ class FakeMain(main.Main): + self.lr = local_rescan.LocalRescan(self.vm, self.fs, + self.event_q, self.action_q) + +- self.eventlog_listener = None + self.status_listener = FakeStatusListener() + + def _connect_aq(self, _): + +=== removed directory 'tests/platform/linux/eventlog' +=== removed file 'tests/platform/linux/eventlog/__init__.py' +--- old/tests/platform/linux/eventlog/__init__.py 2012-04-09 20:07:05 +0000 ++++ new/tests/platform/linux/eventlog/__init__.py 1970-01-01 00:00:00 +0000 +@@ -1,27 +0,0 @@ +-# Copyright 2010-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Tests module.""" + +=== removed file 'tests/platform/linux/eventlog/test_zg_listener.py' +--- old/tests/platform/linux/eventlog/test_zg_listener.py 2012-04-09 20:07:05 +0000 ++++ new/tests/platform/linux/eventlog/test_zg_listener.py 1970-01-01 00:00:00 +0000 +@@ -1,1215 +0,0 @@ +-# -*- coding: utf-8 -*- +-# +-# Copyright 2010-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Test the event logging from SyncDaemon into Zeitgeist.""" +- +-import logging +-import os +-import sys +-import uuid +- +-from os.path import basename +-from twisted.internet import defer +-from zeitgeist.datamodel import Interpretation, Manifestation +- +-# python-zeitgeist on lucid has no mimetypes module, and it's usually +-# disabled, but fake it for running tests on lucid +-try: +- import zeitgeist.mimetypes +- assert(zeitgeist.mimetypes is not None) # make pyflakes happy +-except ImportError: +- +- class FakeMimetypes(object): +- """A fake zg.mimetypes module.""" +- +- def get_interpretation_for_mimetype(self, mimetype): +- """This fake always returns AUDIO.""" +- return Interpretation.AUDIO +- +- sys.modules["zeitgeist.mimetypes"] = FakeMimetypes() +- +-from contrib.testing.testcase import ( +- FakeMain, FakeMainTestCase, BaseTwistedTestCase) +-from ubuntuone.devtools.handlers import MementoHandler +-from ubuntuone.platform import expand_user +-from ubuntuone.storageprotocol import client, delta +-from ubuntuone.storageprotocol.request import ROOT +-from ubuntuone.storageprotocol.sharersp import NotifyShareHolder +-from ubuntuone.syncdaemon.action_queue import ( +- RequestQueue, Upload, MakeFile, MakeDir) +-from ubuntuone.eventlog.zg_listener import ( +- zglog, ZeitgeistListener, ACTOR_UBUNTUONE, +- EVENT_INTERPRETATION_U1_FOLDER_SHARED, +- EVENT_INTERPRETATION_U1_FOLDER_UNSHARED, +- EVENT_INTERPRETATION_U1_SHARE_ACCEPTED, +- EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED, +- EVENT_INTERPRETATION_U1_CONFLICT_RENAME, +- EVENT_INTERPRETATION_U1_UDF_CREATED, +- EVENT_INTERPRETATION_U1_UDF_DELETED, +- EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED, +- EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED, +- MANIFESTATION_U1_CONTACT_DATA_OBJECT, DIRECTORY_MIMETYPE, +- INTERPRETATION_U1_CONTACT, URI_PROTOCOL_U1, +- STORAGE_DELETED, STORAGE_NETWORK, STORAGE_LOCAL) +-from ubuntuone.syncdaemon.sync import Sync +-from ubuntuone.syncdaemon.volume_manager import ( +- ACCESS_LEVEL_RO, +- get_udf_path, Share, Shared, UDF, +-) +-from tests.syncdaemon.test_action_queue import ( +- ConnectedBaseTestCase, +- FakeSemaphore, +- FakeTempFile, +- TestingProtocol, +-) +- +-VOLUME = uuid.UUID('12345678-1234-1234-1234-123456789abc') +- +- +-class MockLogger(object): +- """A mock logger that stores whatever is logged into it.""" +- +- def __init__(self): +- """Initialize this instance.""" +- self.events = [] +- self.deferreds = [] +- +- def log(self, event): +- """Log the event.""" +- self.events.append(event) +- if self.deferreds: +- self.callback_next_deferred(event) +- +- def callback_next_deferred(self, event): +- """Pop the next deferred and callback it.""" +- d = self.deferreds.pop() +- if d: +- d.callback(event) +- +- +-def listen_for(event_q, event, callback, count=1, collect=False): +- """Setup a EQ listener for the specified event.""" +- class Listener(object): +- """A basic listener to handle the pushed event.""" +- +- def __init__(self): +- self.hits = 0 +- self.events = [] +- +- def _handle_event(self, *args, **kwargs): +- self.hits += 1 +- if collect: +- self.events.append((args, kwargs)) +- if self.hits == count: +- event_q.unsubscribe(self) +- if collect: +- callback(self.events) +- elif kwargs: +- callback((args, kwargs)) +- else: +- callback(args) +- +- listener = Listener() +- setattr(listener, 'handle_' + event, listener._handle_event) +- event_q.subscribe(listener) +- return listener +- +- +-class ZeitgeistListenerTestCase(FakeMainTestCase): +- """Tests for ZeitgeistListener.""" +- +- @defer.inlineCallbacks +- def setUp(self): +- """Initialize this instance.""" +- yield super(ZeitgeistListenerTestCase, self).setUp() +- self.patch(zglog, "ZeitgeistLogger", MockLogger) +- self.listener = ZeitgeistListener(self.fs, self.vm) +- self.event_q.subscribe(self.listener) +- self.patch(self.event_q, "ignored_base_exception", RuntimeError) +- +- def _listen_for(self, *args, **kwargs): +- return listen_for(self.main.event_q, *args, **kwargs) +- +- +-class ZeitgeistSharesTestCase(ZeitgeistListenerTestCase): +- """Tests for all Share-related zeitgeist events.""" +- +- @defer.inlineCallbacks +- def test_share_created_with_username_is_logged(self): +- """A ShareCreated event is logged.""" +- fake_username = "fake user" +- path = os.path.join(self.vm.root.path, 'shared_path') +- sample_node_id = "node id" +- self.main.fs.create(path, "") +- self.main.fs.set_node_id(path, sample_node_id) +- +- def fake_create_share(node_id, user, name, access_level, marker, path): +- """Fake the creation of the share on the server.""" +- self.assertIn(marker, self.vm.marker_share_map) +- share_id = self.fs.get_by_mdid(marker).share_id +- self.main.event_q.push('AQ_CREATE_SHARE_OK', +- share_id=share_id, +- marker=marker) +- +- d = defer.Deferred() +- self._listen_for('AQ_CREATE_SHARE_OK', d.callback, 1, collect=True) +- self.patch(self.main.action_q, "create_share", fake_create_share) +- self.vm.create_share(path, fake_username, 'shared_name', +- ACCESS_LEVEL_RO) +- +- yield d +- +- self.assert_folder_shared_is_logged(path, fake_username) +- +- def test_share_created_with_email_is_logged(self): +- """A ShareCreated event is logged.""" +- fake_username = "fakeuser@somewhere.com" +- path = os.path.join(self.vm.root.path, 'shared_path') +- sample_node_id = "node id" +- self.main.fs.create(path, "") +- self.main.fs.set_node_id(path, sample_node_id) +- +- def fake_create_share(node_id, user, name, access_level, marker, path): +- """Fake the creation of the share on the server.""" +- self.assertIn(marker, self.vm.marker_share_map) +- self.main.event_q.push('AQ_SHARE_INVITATION_SENT', +- marker=marker) +- +- self.patch(self.main.action_q, "create_share", fake_create_share) +- self.vm.create_share(path, fake_username, 'shared_name', +- ACCESS_LEVEL_RO) +- +- self.assert_folder_shared_is_logged(path, fake_username) +- +- def assert_folder_shared_is_logged(self, path, fake_username): +- """Assert that the FolderShared event was logged.""" +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- foldername = basename(path) +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_FOLDER_SHARED) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- folder = event.subjects[0] +- self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(folder.manifestation, +- Manifestation.REMOTE_DATA_OBJECT) +- self.assertTrue(folder.origin.endswith(path)) +- self.assertEqual(folder.text, foldername) +- self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(folder.storage, STORAGE_NETWORK) +- +- other_user = event.subjects[1] +- self.assertEqual(other_user.uri, "mailto:" + fake_username) +- self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT) +- self.assertEqual(other_user.manifestation, +- MANIFESTATION_U1_CONTACT_DATA_OBJECT) +- self.assertEqual(other_user.text, fake_username) +- +- @defer.inlineCallbacks +- def test_share_deleted_is_logged(self): +- """Test VolumeManager.delete_share.""" +- sample_share_id = "share id" +- sample_node_id = "node id" +- fake_username = "fake user" +- folder_name = "shared_path" +- path = os.path.join(self.vm.root.path, folder_name) +- self.main.fs.create(path, "") +- self.main.fs.set_node_id(path, sample_node_id) +- share = Shared(path=path, volume_id=sample_share_id, +- node_id=sample_node_id, other_username=fake_username) +- yield self.vm.add_shared(share) +- +- def fake_delete_share(share_id): +- """Fake delete_share.""" +- self.assertEqual(share_id, share.volume_id) +- self.main.event_q.push('AQ_DELETE_SHARE_OK', share_id=share_id) +- +- self.patch(self.main.action_q, 'delete_share', fake_delete_share) +- d = defer.Deferred() +- self._listen_for('VM_SHARE_DELETED', d.callback, 1, collect=True) +- self.vm.delete_share(share.volume_id) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_FOLDER_UNSHARED) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- folder = event.subjects[0] +- self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(folder.manifestation, +- Manifestation.REMOTE_DATA_OBJECT) +- self.assertTrue(folder.origin.endswith(path)) +- self.assertEqual(folder.text, folder_name) +- self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(folder.storage, STORAGE_NETWORK) +- +- other_user = event.subjects[1] +- self.assertEqual(other_user.uri, "mailto:" + fake_username) +- self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT) +- self.assertEqual(other_user.manifestation, +- MANIFESTATION_U1_CONTACT_DATA_OBJECT) +- self.assertEqual(other_user.text, fake_username) +- +- @defer.inlineCallbacks +- def test_share_accepted_is_logged(self): +- """Test that an accepted share event is logged.""" +- # initialize the the root +- self.vm._got_root('root_uuid') +- fake_username = "fake user" +- folder_name = "shared_path" +- path = os.path.join(self.vm.root.path, folder_name) +- self.main.fs.create(path, "") +- share_path = os.path.join(self.shares_dir, folder_name) +- share = Share(path=share_path, volume_id='volume_id', node_id="node_id", +- other_username=fake_username) +- yield self.vm.add_share(share) +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_SHARE_ACCEPTED) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- folder = event.subjects[0] +- self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(folder.manifestation, +- Manifestation.REMOTE_DATA_OBJECT) +- self.assertTrue(folder.origin.endswith(share_path)) +- self.assertEqual(folder.text, folder_name) +- self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(folder.storage, STORAGE_NETWORK) +- +- other_user = event.subjects[1] +- self.assertEqual(other_user.uri, "mailto:" + fake_username) +- self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT) +- self.assertEqual(other_user.manifestation, +- MANIFESTATION_U1_CONTACT_DATA_OBJECT) +- self.assertEqual(other_user.text, fake_username) +- +- @defer.inlineCallbacks +- def test_share_unaccepted_is_logged(self): +- """Test that an unaccepted share event is logged.""" +- fake_username = "fake user" +- folder_name = u"share" +- d = defer.Deferred() +- +- share_path = os.path.join(self.main.shares_dir, folder_name) +- holder = NotifyShareHolder.from_params(uuid.uuid4(), +- uuid.uuid4(), +- u'fake_share', +- fake_username, +- u'visible_name', 'Read') +- +- share = Share.from_notify_holder(holder, share_path) +- yield self.main.vm.add_share(share) +- self._listen_for('VM_VOLUME_DELETED', d.callback, 1, collect=True) +- self.main.event_q.push('SV_SHARE_DELETED', share_id=holder.share_id) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 2) +- event = self.listener.zg.events[1] +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- folder = event.subjects[0] +- self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(folder.manifestation, +- Manifestation.REMOTE_DATA_OBJECT) +- self.assertTrue(folder.origin.endswith(share_path)) +- self.assertEqual(folder.text, folder_name) +- self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(folder.storage, STORAGE_NETWORK) +- +- other_user = event.subjects[1] +- self.assertEqual(other_user.uri, "mailto:" + fake_username) +- self.assertEqual(other_user.interpretation, INTERPRETATION_U1_CONTACT) +- self.assertEqual(other_user.manifestation, +- MANIFESTATION_U1_CONTACT_DATA_OBJECT) +- self.assertEqual(other_user.text, fake_username) +- +- +-class ZeitgeistUDFsTestCase(ZeitgeistListenerTestCase): +- """Tests for all UDFs-related zeitgeist events.""" +- +- def _create_udf(self, id, node_id, suggested_path, subscribed=True): +- """Create an UDF and returns it and the volume.""" +- path = get_udf_path(suggested_path) +- # make sure suggested_path is unicode +- if isinstance(suggested_path, str): +- suggested_path = suggested_path.decode('utf-8') +- udf = UDF(str(id), str(node_id), suggested_path, path, subscribed) +- return udf +- +- @defer.inlineCallbacks +- def test_udf_create_is_logged(self): +- """Test for Folders.create.""" +- folder_name = u'ñoño'.encode('utf-8') +- path = os.path.join(self.home_dir, folder_name) +- id = uuid.uuid4() +- node_id = uuid.uuid4() +- +- def create_udf(path, name, marker): +- """Fake create_udf.""" +- # check that the marker is the full path to the udf +- expanded_path = expand_user(path.encode('utf-8')) +- udf_path = os.path.join(expanded_path, name.encode('utf-8')) +- if str(marker) != udf_path: +- d.errback(ValueError("marker != path - " +- "marker: %r path: %r" % (marker, udf_path))) +- self.main.event_q.push("AQ_CREATE_UDF_OK", **dict(volume_id=id, +- node_id=node_id, +- marker=marker)) +- +- self.patch(self.main.action_q, "create_udf", create_udf) +- +- d = defer.Deferred() +- self.listener.zg.deferreds.append(d) +- self.vm.create_udf(path) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_UDF_CREATED) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- folder = event.subjects[0] +- self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(folder.manifestation, +- Manifestation.REMOTE_DATA_OBJECT) +- self.assertTrue(folder.origin.endswith(path)) +- self.assertEqual(folder.text, folder_name) +- self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(folder.storage, STORAGE_NETWORK) +- +- @defer.inlineCallbacks +- def test_udf_delete_is_logged(self): +- """Test for Folders.delete.""" +- id = uuid.uuid4() +- node_id = uuid.uuid4() +- folder_name = u'ñoño'.encode('utf-8') +- path = os.path.join(self.home_dir, folder_name) +- +- d = defer.Deferred() +- self.listener.zg.deferreds.append(d) +- +- def create_udf(path, name, marker): +- """Fake create_udf.""" +- # check that the marker is the full path to the udf +- expanded_path = expand_user(path.encode('utf-8')) +- udf_path = os.path.join(expanded_path, name.encode('utf-8')) +- if str(marker) != udf_path: +- d.errback(ValueError("marker != path - " +- "marker: %r path: %r" % (marker, udf_path))) +- self.main.event_q.push("AQ_CREATE_UDF_OK", **dict(volume_id=id, +- node_id=node_id, +- marker=marker)) +- +- self.patch(self.main.action_q, "create_udf", create_udf) +- +- self.vm.create_udf(path) +- yield d +- +- def delete_volume(volume_id, path): +- """Fake delete_volume.""" +- self.main.event_q.push("AQ_DELETE_VOLUME_OK", volume_id=id) +- +- self.patch(self.main.action_q, "delete_volume", delete_volume) +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- d2 = defer.Deferred() +- self.listener.zg.deferreds.append(d2) +- self.vm.delete_volume(str(id)) +- yield d2 +- +- self.assertEqual(len(self.listener.zg.events), 2) +- event = self.listener.zg.events[1] +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_UDF_DELETED) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- folder = event.subjects[0] +- self.assertTrue(folder.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(folder.manifestation, +- Manifestation.DELETED_RESOURCE) +- self.assertTrue(folder.origin.endswith(path)) +- self.assertEqual(folder.text, folder_name) +- self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(folder.storage, STORAGE_DELETED) +- +- @defer.inlineCallbacks +- def test_udf_subscribe_is_logged(self): +- """Test for Folders.subscribe.""" +- folder_name = u"ñoño" +- suggested_path = u'~/' + folder_name +- udf = self._create_udf(uuid.uuid4(), 'node_id', suggested_path, +- subscribed=False) +- yield self.main.vm.add_udf(udf) +- d = defer.Deferred() +- self.listener.zg.deferreds.append(d) +- self.vm.subscribe_udf(udf.volume_id) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 2) +- event = self.listener.zg.events[1] +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- folder = event.subjects[0] +- self.assertTrue(folder.uri.endswith(udf.path)) +- self.assertEqual(folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(folder.manifestation, +- Manifestation.FILE_DATA_OBJECT) +- self.assertTrue(folder.origin.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(folder.text.decode('utf-8'), folder_name) +- self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(folder.storage, STORAGE_LOCAL) +- +- @defer.inlineCallbacks +- def test_udf_unsubscribe_is_logged(self): +- """Test for Folders.unsubscribe.""" +- suggested_path = u'~/ñoño' +- udf = self._create_udf(uuid.uuid4(), 'node_id', suggested_path, +- subscribed=True) +- folder_name = basename(udf.path) +- yield self.main.vm.add_udf(udf) +- d = defer.Deferred() +- self._listen_for('VM_UDF_UNSUBSCRIBED', d.callback, 1, collect=True) +- self.vm.unsubscribe_udf(udf.volume_id) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 2) +- event = self.listener.zg.events[1] +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- folder = event.subjects[0] +- self.assertTrue(folder.uri.endswith(udf.path)) +- self.assertEqual(folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(folder.manifestation, +- Manifestation.DELETED_RESOURCE) +- self.assertTrue(folder.origin.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(folder.text, folder_name) +- self.assertEqual(folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(folder.storage, STORAGE_DELETED) +- +- +-class ZeitgeistRemoteFileSyncTestCase(ConnectedBaseTestCase): +- """File sync events are logged into Zeitgeist.""" +- +- @defer.inlineCallbacks +- def setUp(self): +- """Initialize this test instance.""" +- yield super(ZeitgeistRemoteFileSyncTestCase, self).setUp() +- self.rq = request_queue = RequestQueue(action_queue=self.action_queue) +- self.rq.transfers_semaphore = FakeSemaphore() +- +- class MyUpload(Upload): +- """Just to allow monkeypatching.""" +- +- self.share_id = "" +- self.command = MyUpload(request_queue, share_id=self.share_id, +- node_id='a_node_id', previous_hash='prev_hash', +- hash='yadda', crc32=0, size=0, path='path') +- self.command.make_logger() +- self.command.tempfile = FakeTempFile(self.mktemp('tmpdir')) +- self.fsm = self.action_queue.main.fs +- self.vm = self.action_queue.main.vm +- self.patch(zglog, "ZeitgeistLogger", MockLogger) +- self.listener = ZeitgeistListener(self.fsm, self.vm) +- self.action_queue.event_queue.subscribe(self.listener) +- self.root_id = "roootid" +- self.sync = Sync(main=self.main) +- +- def test_syncdaemon_creates_file_on_server_is_logged(self): +- """Files created by SyncDaemon on the server are logged.""" +- filename = "filename.mp3" +- path = os.path.join(self.vm.root.path, filename) +- self.fsm.create(path, "") +- self.fsm.set_node_id(path, "a_node_id") +- +- request = client.MakeFile(self.action_queue.client, self.share_id, +- 'parent', filename) +- request.new_id = 'a_node_id' +- request.new_generation = 13 +- +- # create a command and trigger it success +- cmd = MakeFile(self.rq, self.share_id, 'parent', filename, +- 'marker', path) +- cmd.handle_success(request) +- +- # create a request and fill it with succesful information +- aq_client = TestingProtocol() +- request = client.PutContent(aq_client, self.share_id, +- 'node', 'prvhash', 'newhash', 'crc32', +- 'size', 'deflated', 'fd') +- request.new_generation = 13 +- +- # trigger success in the command +- self.command.handle_success(request) +- +- # check for successful event +- kwargs = dict(share_id=self.command.share_id, node_id='a_node_id', +- hash='yadda', new_generation=13) +- +- info = dict(marker='marker', new_id='a_node_id', new_generation=13, +- volume_id=self.share_id) +- events = [ +- ('AQ_FILE_NEW_OK', info), +- ('AQ_UPLOAD_FINISHED', kwargs), +- ] +- self.assertEqual(events, self.command.action_queue.event_queue.events) +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.CREATE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.SCHEDULED_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- remote_file = event.subjects[0] +- self.assertTrue(remote_file.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(remote_file.interpretation, Interpretation.AUDIO) +- self.assertEqual(remote_file.manifestation, +- Manifestation.REMOTE_DATA_OBJECT) +- self.assertTrue(remote_file.origin.endswith(filename)) +- self.assertEqual(remote_file.text, filename) +- self.assertEqual(remote_file.mimetype, "audio/mpeg") +- self.assertEqual(remote_file.storage, STORAGE_NETWORK) +- +- def test_syncdaemon_creates_dir_on_server_is_logged(self): +- """Dirs created by SyncDaemon on the server are logged.""" +- dirname = "dirname" +- path = os.path.join(self.vm.root.path, dirname) +- self.fsm.create(path, "") +- self.fsm.set_node_id(path, "a_node_id") +- +- request = client.MakeDir(self.action_queue.client, self.share_id, +- 'parent', dirname) +- request.new_id = 'a_node_id' +- request.new_generation = 13 +- +- # create a command and trigger it success +- cmd = MakeDir(self.rq, self.share_id, 'parent', +- dirname, 'marker', path) +- cmd.handle_success(request) +- +- # check for successful event +- info = dict(marker='marker', new_id='a_node_id', new_generation=13, +- volume_id=self.share_id) +- events = [('AQ_DIR_NEW_OK', info)] +- self.assertEqual(events, self.command.action_queue.event_queue.events) +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.CREATE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.SCHEDULED_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- remote_folder = event.subjects[0] +- self.assertTrue(remote_folder.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(remote_folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(remote_folder.manifestation, +- Manifestation.REMOTE_DATA_OBJECT) +- self.assertTrue(remote_folder.origin.endswith(dirname)) +- self.assertEqual(remote_folder.text, dirname) +- self.assertEqual(remote_folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(remote_folder.storage, STORAGE_NETWORK) +- +- def test_syncdaemon_modifies_on_server_is_logged(self): +- """Files modified by SyncDaemon on the server are logged.""" +- filename = "filename.mp3" +- path = os.path.join(self.vm.root.path, filename) +- self.fsm.create(path, "") +- self.fsm.set_node_id(path, "a_node_id") +- +- # create a request and fill it with succesful information +- aq_client = TestingProtocol() +- request = client.PutContent(aq_client, self.share_id, +- 'node', 'prvhash', 'newhash', 'crc32', +- 'size', 'deflated', 'fd') +- request.new_generation = 13 +- +- # trigger success in the command +- self.command.handle_success(request) +- +- # check for successful event +- kwargs = dict(share_id=self.command.share_id, node_id='a_node_id', +- hash='yadda', new_generation=13) +- +- events = [('AQ_UPLOAD_FINISHED', kwargs)] +- self.assertEqual(events, self.command.action_queue.event_queue.events) +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.MODIFY_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.SCHEDULED_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- remote_file = event.subjects[0] +- self.assertTrue(remote_file.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(remote_file.interpretation, Interpretation.AUDIO) +- self.assertEqual(remote_file.manifestation, +- Manifestation.REMOTE_DATA_OBJECT) +- self.assertTrue(remote_file.origin.endswith(filename)) +- self.assertEqual(remote_file.text, filename) +- self.assertEqual(remote_file.mimetype, "audio/mpeg") +- self.assertEqual(remote_file.storage, STORAGE_NETWORK) +- +- @defer.inlineCallbacks +- def test_syncdaemon_deletes_file_on_server_is_logged(self): +- """Files deleted by SD on the server are logged.""" +- file_name = "filename.mp3" +- d = defer.Deferred() +- listen_for(self.main.event_q, 'AQ_UNLINK_OK', d.callback) +- +- path = os.path.join(self.main.vm.root.path, "filename.mp3") +- self.main.event_q.push("AQ_UNLINK_OK", share_id="", +- parent_id="parent_id", +- node_id="node_id", new_generation=13, +- was_dir=False, old_path=path) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.DELETE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.SCHEDULED_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- remote_file = event.subjects[0] +- self.assertTrue(remote_file.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(remote_file.interpretation, Interpretation.AUDIO) +- self.assertEqual(remote_file.manifestation, +- Manifestation.DELETED_RESOURCE) +- self.assertTrue(remote_file.origin.endswith(file_name)) +- self.assertEqual(remote_file.text, file_name) +- self.assertEqual(remote_file.mimetype, "audio/mpeg") +- self.assertEqual(remote_file.storage, STORAGE_DELETED) +- +- @defer.inlineCallbacks +- def test_syncdaemon_deletes_dir_on_server_is_logged(self): +- """Directories deleted by SD on the server are logged.""" +- folder_name = "folder name" +- d = defer.Deferred() +- listen_for(self.main.event_q, 'AQ_UNLINK_OK', d.callback) +- +- path = os.path.join(self.main.vm.root.path, "folder name") +- self.main.event_q.push("AQ_UNLINK_OK", share_id="", +- parent_id="parent_id", +- node_id="node_id", new_generation=13, +- was_dir=True, old_path=path) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.DELETE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.SCHEDULED_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- remote_folder = event.subjects[0] +- self.assertTrue(remote_folder.uri.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(remote_folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(remote_folder.manifestation, +- Manifestation.DELETED_RESOURCE) +- self.assertTrue(remote_folder.origin.endswith(folder_name)) +- self.assertEqual(remote_folder.text, folder_name) +- self.assertEqual(remote_folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(remote_folder.storage, STORAGE_DELETED) +- +- +-class ZeitgeistLocalFileSyncTestCase(BaseTwistedTestCase): +- """Zeitgeist events coming from the server.""" +- timeout = 5 +- +- @defer.inlineCallbacks +- def setUp(self): +- """Initialize this instance.""" +- yield super(ZeitgeistLocalFileSyncTestCase, self).setUp() +- self.root = self.mktemp('root') +- self.shares = self.mktemp('shares') +- self.data = self.mktemp('data') +- self.partials_dir = self.mktemp('partials_dir') +- self.handler = MementoHandler() +- self.handler.setLevel(logging.ERROR) +- FakeMain._sync_class = Sync +- self.main = FakeMain(root_dir=self.root, shares_dir=self.shares, +- data_dir=self.data, +- partials_dir=self.partials_dir) +- self._logger = logging.getLogger('ubuntuone.SyncDaemon') +- self._logger.addHandler(self.handler) +- +- self.root_id = root_id = "roootid" +- self.main.vm._got_root(root_id) +- self.filemp3delta = delta.FileInfoDelta( +- generation=5, is_live=True, file_type=delta.FILE, +- parent_id=self.root_id, share_id=ROOT, node_id=uuid.uuid4(), +- name=u"fileñ.mp3", is_public=False, content_hash="hash", +- crc32=1, size=10, last_modified=0) +- +- self.dirdelta = delta.FileInfoDelta( +- generation=6, is_live=True, file_type=delta.DIRECTORY, +- parent_id=root_id, share_id=ROOT, node_id=uuid.uuid4(), +- name=u"directory_ñ", is_public=False, content_hash="hash", +- crc32=1, size=10, last_modified=0) +- +- self.patch(zglog, "ZeitgeistLogger", MockLogger) +- self.listener = ZeitgeistListener(self.main.fs, self.main.vm) +- self.main.event_q.subscribe(self.listener) +- +- @defer.inlineCallbacks +- def tearDown(self): +- """Clean up this instance.""" +- self._logger.removeHandler(self.handler) +- self.main.shutdown() +- FakeMain._sync_class = None +- for record in self.handler.records: +- exc_info = getattr(record, 'exc_info', None) +- if exc_info is not None: +- raise exc_info[0], exc_info[1], exc_info[2] +- yield super(ZeitgeistLocalFileSyncTestCase, self).tearDown() +- +- @defer.inlineCallbacks +- def test_syncdaemon_creates_file_locally_is_logged(self): +- """Files created locally by SyncDaemon are logged.""" +- file_name = self.filemp3delta.name.encode('utf8') +- d = defer.Deferred() +- d2 = defer.Deferred() +- listen_for(self.main.event_q, 'SV_FILE_NEW', d.callback) +- listen_for(self.main.event_q, 'AQ_DOWNLOAD_FINISHED', d2.callback) +- +- deltas = [self.filemp3delta] +- kwargs = dict(volume_id=ROOT, delta_content=deltas, end_generation=11, +- full=True, free_bytes=10) +- self.main.sync.handle_AQ_DELTA_OK(**kwargs) +- +- # check that the file is created +- node = self.main.fs.get_by_node_id(ROOT, self.filemp3delta.node_id) +- self.assertEqual(node.path, file_name) +- self.assertEqual(node.is_dir, False) +- self.assertEqual(node.generation, self.filemp3delta.generation) +- +- yield d # wait for SV_FILE_NEW +- +- dlargs = dict( +- share_id=self.filemp3delta.share_id, +- node_id=self.filemp3delta.node_id, +- server_hash="server hash") +- self.main.event_q.push("AQ_DOWNLOAD_FINISHED", **dlargs) +- +- yield d2 # wait for AQ_DOWNLOAD_FINISHED +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.CREATE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.WORLD_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- local_file = event.subjects[0] +- self.assertTrue(local_file.uri.endswith(file_name)) +- self.assertEqual(local_file.interpretation, Interpretation.AUDIO) +- self.assertEqual(local_file.manifestation, +- Manifestation.FILE_DATA_OBJECT) +- self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(local_file.text, file_name) +- self.assertEqual(local_file.mimetype, "audio/mpeg") +- self.assertEqual(local_file.storage, STORAGE_LOCAL) +- +- @defer.inlineCallbacks +- def test_syncdaemon_creates_dir_locally_is_logged(self): +- """Dirs created locally by SyncDaemon are logged.""" +- folder_name = self.dirdelta.name.encode('utf8') +- d = defer.Deferred() +- listen_for(self.main.event_q, 'SV_DIR_NEW', d.callback) +- +- deltas = [self.dirdelta] +- kwargs = dict(volume_id=ROOT, delta_content=deltas, end_generation=11, +- full=True, free_bytes=10) +- self.main.sync.handle_AQ_DELTA_OK(**kwargs) +- +- # check that the dir is created +- node = self.main.fs.get_by_node_id(ROOT, self.dirdelta.node_id) +- self.assertEqual(node.path, folder_name) +- self.assertEqual(node.is_dir, True) +- self.assertEqual(node.generation, self.dirdelta.generation) +- +- yield d # wait for SV_DIR_NEW +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.CREATE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.WORLD_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- local_folder = event.subjects[0] +- self.assertTrue(local_folder.uri.endswith(folder_name)) +- self.assertEqual(local_folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(local_folder.manifestation, +- Manifestation.FILE_DATA_OBJECT) +- self.assertTrue(local_folder.origin.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(local_folder.text, folder_name) +- self.assertEqual(local_folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(local_folder.storage, STORAGE_LOCAL) +- +- @defer.inlineCallbacks +- def test_syncdaemon_modifies_locally_is_logged(self): +- """Files modified locally by SyncDaemon are logged.""" +- file_name = self.filemp3delta.name.encode('utf8') +- d = defer.Deferred() +- d2 = defer.Deferred() +- listen_for(self.main.event_q, 'SV_FILE_NEW', d.callback) +- listen_for(self.main.event_q, 'AQ_DOWNLOAD_FINISHED', d2.callback) +- +- deltas = [self.filemp3delta] +- kwargs = dict(volume_id=ROOT, delta_content=deltas, end_generation=11, +- full=True, free_bytes=10) +- self.main.sync.handle_AQ_DELTA_OK(**kwargs) +- +- # check that the file is modified +- node = self.main.fs.get_by_node_id(ROOT, self.filemp3delta.node_id) +- self.assertEqual(node.path, file_name) +- self.assertEqual(node.is_dir, False) +- self.assertEqual(node.generation, self.filemp3delta.generation) +- +- yield d # wait for SV_FILE_NEW +- +- # remove from the recent list +- local_file_id = (self.filemp3delta.share_id, self.filemp3delta.node_id) +- self.listener.newly_created_local_files.remove(local_file_id) +- +- dlargs = dict( +- share_id=self.filemp3delta.share_id, +- node_id=self.filemp3delta.node_id, +- server_hash="server hash") +- self.main.event_q.push("AQ_DOWNLOAD_FINISHED", **dlargs) +- +- yield d2 # wait for AQ_DOWNLOAD_FINISHED +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.MODIFY_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.WORLD_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- local_file = event.subjects[0] +- self.assertTrue(local_file.uri.endswith(file_name)) +- self.assertEqual(local_file.interpretation, Interpretation.AUDIO) +- self.assertEqual(local_file.manifestation, +- Manifestation.FILE_DATA_OBJECT) +- self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(local_file.text, file_name) +- self.assertEqual(local_file.mimetype, "audio/mpeg") +- self.assertEqual(local_file.storage, STORAGE_LOCAL) +- +- @defer.inlineCallbacks +- def test_syncdaemon_deletes_file_locally_is_logged(self): +- """Files deleted locally by SyncDaemon are logged.""" +- file_name = self.filemp3delta.name.encode("utf-8") +- d = defer.Deferred() +- listen_for(self.main.event_q, 'SV_FILE_DELETED', d.callback) +- +- filename = self.filemp3delta.name.encode("utf-8") +- path = os.path.join(self.main.vm.root.path, filename) +- self.main.event_q.push("SV_FILE_DELETED", volume_id="", +- node_id="node_id", was_dir=False, +- old_path=path) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.DELETE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.WORLD_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- local_file = event.subjects[0] +- self.assertTrue(local_file.uri.endswith(file_name)) +- self.assertEqual(local_file.interpretation, Interpretation.AUDIO) +- self.assertEqual(local_file.manifestation, +- Manifestation.DELETED_RESOURCE) +- self.assertTrue(local_file.origin.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(local_file.text, file_name) +- self.assertEqual(local_file.mimetype, "audio/mpeg") +- self.assertEqual(local_file.storage, STORAGE_DELETED) +- +- @defer.inlineCallbacks +- def test_syncdaemon_deletes_dir_locally_is_logged(self): +- """Dirs deleted locally by SyncDaemon are logged.""" +- folder_name = "folder name" +- d = defer.Deferred() +- listen_for(self.main.event_q, 'SV_FILE_DELETED', d.callback) +- +- path = os.path.join(self.main.vm.root.path, "folder name") +- self.main.event_q.push("SV_FILE_DELETED", volume_id="", +- node_id="node_id", was_dir=True, +- old_path=path) +- +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- Interpretation.DELETE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.WORLD_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- local_folder = event.subjects[0] +- self.assertTrue(local_folder.uri.endswith(folder_name)) +- self.assertEqual(local_folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(local_folder.manifestation, +- Manifestation.DELETED_RESOURCE) +- self.assertTrue(local_folder.origin.startswith(URI_PROTOCOL_U1)) +- self.assertEqual(local_folder.text, folder_name) +- self.assertEqual(local_folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(local_folder.storage, STORAGE_DELETED) +- +- @defer.inlineCallbacks +- def test_file_sync_conflict_is_logged(self): +- """Files renamed because of conflict are logged.""" +- file_name = "sample.mp3" +- d = defer.Deferred() +- listen_for(self.main.event_q, 'FSM_FILE_CONFLICT', d.callback) +- +- testfile = os.path.join(self.main.vm.root.path, file_name) +- mdid = self.main.fs.create(testfile, "") +- self.main.fs.set_node_id(testfile, "uuid") +- with open(testfile, "w") as fh: +- fh.write("this is music!") +- +- self.main.fs.move_to_conflict(mdid) +- +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_CONFLICT_RENAME) +- self.assertEqual(event.manifestation, +- Manifestation.WORLD_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- local_file = event.subjects[0] +- new_name = testfile + self.main.fs.CONFLICT_SUFFIX +- self.assertTrue(local_file.uri.endswith(new_name)) +- self.assertEqual(local_file.interpretation, Interpretation.AUDIO) +- self.assertEqual(local_file.manifestation, +- Manifestation.FILE_DATA_OBJECT) +- self.assertTrue(local_file.origin.endswith(testfile)) +- self.assertEqual(local_file.text, +- file_name + self.main.fs.CONFLICT_SUFFIX) +- self.assertEqual(local_file.mimetype, "audio/mpeg") +- self.assertEqual(local_file.storage, STORAGE_LOCAL) +- +- @defer.inlineCallbacks +- def test_dir_sync_conflict_is_logged(self): +- """Dirs renamed because of conflict are logged.""" +- folder_name = "sampledir" +- d = defer.Deferred() +- listen_for(self.main.event_q, 'FSM_DIR_CONFLICT', d.callback) +- +- testdir = os.path.join(self.main.vm.root.path, folder_name) +- mdid = self.main.fs.create(testdir, "", is_dir=True) +- self.main.fs.set_node_id(testdir, "uuid") +- os.mkdir(testdir) +- +- self.main.fs.move_to_conflict(mdid) +- +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 1) +- event = self.listener.zg.events[0] +- +- self.assertEqual(event.interpretation, +- EVENT_INTERPRETATION_U1_CONFLICT_RENAME) +- self.assertEqual(event.manifestation, +- Manifestation.WORLD_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- local_folder = event.subjects[0] +- new_name = testdir + self.main.fs.CONFLICT_SUFFIX +- self.assertTrue(local_folder.uri.endswith(new_name)) +- self.assertEqual(local_folder.interpretation, Interpretation.FOLDER) +- self.assertEqual(local_folder.manifestation, +- Manifestation.FILE_DATA_OBJECT) +- self.assertTrue(local_folder.origin.endswith(testdir)) +- self.assertEqual(local_folder.text, +- folder_name + self.main.fs.CONFLICT_SUFFIX) +- self.assertEqual(local_folder.mimetype, DIRECTORY_MIMETYPE) +- self.assertEqual(local_folder.storage, STORAGE_LOCAL) +- +- +-class ZeitgeistPublicFilesTestCase(ZeitgeistListenerTestCase): +- """Public files events are logged into Zeitgeist.""" +- +- @defer.inlineCallbacks +- def test_publish_url_is_logged(self): +- """Publishing a file with a url is logged.""" +- share_id = "share" +- node_id = "node_id" +- is_public = True +- public_url = 'http://example.com/foo.mp3' +- +- share_path = os.path.join(self.shares_dir, 'share') +- yield self.main.vm.add_share(Share(path=share_path, volume_id='share', +- other_username='other username')) +- path = os.path.join(share_path, "foo.mp3") +- self.main.fs.create(path, str(share_id)) +- self.main.fs.set_node_id(path, str(node_id)) +- +- d = defer.Deferred() +- self._listen_for('AQ_CHANGE_PUBLIC_ACCESS_OK', d.callback) +- self.main.event_q.push('AQ_CHANGE_PUBLIC_ACCESS_OK', +- share_id=share_id, node_id=node_id, +- is_public=is_public, public_url=public_url) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 2) +- event = self.listener.zg.events[1] +- +- self.assertEqual(event.interpretation, +- Interpretation.CREATE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- public_file = event.subjects[0] +- self.assertEqual(public_file.uri, public_url) +- self.assertEqual(public_file.interpretation, Interpretation.AUDIO) +- self.assertEqual(public_file.manifestation, +- Manifestation.REMOTE_DATA_OBJECT) +- self.assertTrue(public_file.origin.endswith(node_id)) +- self.assertEqual(public_file.text, public_url) +- self.assertEqual(public_file.mimetype, "audio/mpeg") +- self.assertEqual(public_file.storage, STORAGE_NETWORK) +- +- @defer.inlineCallbacks +- def test_unpublish_url_is_logged(self): +- """Unpublishing a file with a url is logged.""" +- share_id = "share" +- node_id = "node_id" +- is_public = False +- public_url = 'http://example.com/foo.mp3' +- +- share_path = os.path.join(self.shares_dir, 'share') +- yield self.main.vm.add_share(Share(path=share_path, volume_id='share', +- other_username='other username')) +- path = os.path.join(share_path, "foo.mp3") +- self.main.fs.create(path, str(share_id)) +- self.main.fs.set_node_id(path, str(node_id)) +- +- d = defer.Deferred() +- self._listen_for('AQ_CHANGE_PUBLIC_ACCESS_OK', d.callback) +- self.main.event_q.push('AQ_CHANGE_PUBLIC_ACCESS_OK', +- share_id=share_id, node_id=node_id, +- is_public=is_public, public_url=public_url) +- yield d +- +- self.assertEqual(len(self.listener.zg.events), 2) +- event = self.listener.zg.events[1] +- +- self.assertEqual(event.interpretation, +- Interpretation.DELETE_EVENT) +- self.assertEqual(event.manifestation, +- Manifestation.USER_ACTIVITY) +- self.assertEqual(event.actor, ACTOR_UBUNTUONE) +- +- public_file = event.subjects[0] +- self.assertEqual(public_file.uri, public_url) +- self.assertEqual(public_file.interpretation, Interpretation.AUDIO) +- self.assertEqual(public_file.manifestation, +- Manifestation.DELETED_RESOURCE) +- self.assertTrue(public_file.origin.endswith(node_id)) +- self.assertEqual(public_file.text, public_url) +- self.assertEqual(public_file.mimetype, "audio/mpeg") +- self.assertEqual(public_file.storage, STORAGE_DELETED) + +=== removed file 'tests/platform/linux/eventlog/test_zglog.py' +--- old/tests/platform/linux/eventlog/test_zglog.py 2012-04-09 20:07:05 +0000 ++++ new/tests/platform/linux/eventlog/test_zglog.py 1970-01-01 00:00:00 +0000 +@@ -1,173 +0,0 @@ +-# -*- coding: utf-8 -*- +-# +-# Author: Alejandro J. Cura +-# +-# Copyright 2010-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Tests for the Zeitgeist logging.""" +- +-import os +-import shutil +-import subprocess +-import tempfile +-import time +- +-from distutils.spawn import find_executable +- +-from twisted.internet import defer +-from zeitgeist.client import ZeitgeistClient +-from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation +- +-from tests.platform.linux.test_dbus import DBusTwistedTestCase +-from ubuntuone.eventlog.zglog import ZeitgeistLogger +- +-SRCDIR = os.environ.get('SRCDIR', os.getcwd()) +- +- +-class NotFoundError(Exception): +- """Not found error.""" +- +- +-class ZeitgeistNotStartedTests(DBusTwistedTestCase): +- """Tests for the zeitgeist logging module.""" +- +- def test_log_does_not_err_when_daemon_not_started(self): +- """zeitgeist-daemon was not started.""" +- timestamp = int(time.time() * 1000) +- subject = Subject.new_for_values( +- uri="file:///tmp/folder1", +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.FILE_DATA_OBJECT, +- origin="ubuntuone:uuid", +- mimetype="inode/directory", +- text="sample folder" +- ) +- sample_event = Event.new_for_values( +- timestamp=timestamp, +- interpretation=Interpretation.ACCESS_EVENT, +- manifestation=Manifestation.USER_ACTIVITY, +- actor="mailto:sample_subject", +- subjects=[subject] +- ) +- +- zg = ZeitgeistLogger() +- d = zg.log(sample_event) +- self.assertEqual(zg.client, None) +- +- def verify(result): +- """Stored result is the empty list, because zg not available.""" +- self.assertEqual(result, []) +- return result +- +- d.addCallback(verify) +- return d +- +- +-def wait_zeitgeist_started(seconds=10): +- """Wait a few seconds until zg is started, or fail if it can't.""" +- client = None +- count = 0 +- while client is None: +- count += 1 +- try: +- client = ZeitgeistClient() +- break +- except RuntimeError: +- if count > seconds*10: +- raise +- time.sleep(0.1) +- +- +-class ZeitgeistTestCase(DBusTwistedTestCase): +- """Tests for the zeitgeist logging module.""" +- +- @defer.inlineCallbacks +- def setUp(self): +- yield super(ZeitgeistTestCase, self).setUp() +- zgdaemon = find_executable("zeitgeist-daemon") +- if not zgdaemon: +- raise NotFoundError("zeitgeist-daemon was not found.") +- +- tempfolder = tempfile.mkdtemp(prefix="test-u1-zeitgeist-") +- tempstdout = tempfile.TemporaryFile(prefix="test-u1-stdout-") +- tempstderr = tempfile.TemporaryFile(prefix="test-u1-stderr-") +- os.environ["ZEITGEIST_DATA_PATH"] = tempfolder +- p = subprocess.Popen([zgdaemon], bufsize=4096, stdout=tempstdout, +- stderr=tempstderr) +- def cleanup(): +- """Wait for the process to finish.""" +- p.terminate() +- p.wait() +- del(os.environ["ZEITGEIST_DATA_PATH"]) +- shutil.rmtree(tempfolder) +- +- wait_zeitgeist_started() +- self.addCleanup(cleanup) +- +- def test_log_records_the_event(self): +- """The log method records the event in zg.""" +- timestamp = int(time.time() * 1000) +- subject = Subject.new_for_values( +- uri="file:///tmp/folder1", +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.FILE_DATA_OBJECT, +- origin="ubuntuone:uuid", +- mimetype="inode/directory", +- text="sample folder" +- ) +- sample_event = Event.new_for_values( +- timestamp=timestamp, +- interpretation=Interpretation.ACCESS_EVENT, +- manifestation=Manifestation.USER_ACTIVITY, +- actor="mailto:sample_subject", +- subjects=[subject] +- ) +- +- sample_template = Event.new_for_values() +- +- zg = ZeitgeistLogger() +- self.assertNotEqual(zg.client, None) +- +- d2 = defer.Deferred() +- +- def logged(id_list): +- """The event was logged to zeitgeist.""" +- +- def events_found(event_list): +- """zg returned the list of events.""" +- self.assertEqual(event_list[0].id, id_list[0]) +- d2.callback("ok") +- +- zg.client.find_events_for_template(sample_template, events_found) +- +- d = zg.log(sample_event) +- d.addCallbacks(logged, d2.errback) +- +- return d2 +- +- +-ZeitgeistTestCase.skip = 'Suite is hanging in nightlies build (LP: #929812).' + +=== removed file 'tests/platform/linux/test_event_logging.py' +--- old/tests/platform/linux/test_event_logging.py 2012-04-09 20:07:05 +0000 ++++ new/tests/platform/linux/test_event_logging.py 1970-01-01 00:00:00 +0000 +@@ -1,92 +0,0 @@ +-# tests.platform.linux.test_event_logging +-# +-# Author: Alejandro J. Cura +-# +-# Copyright 2010-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Test the event logging on linux.""" +- +-import sys +- +-from twisted.trial.unittest import TestCase +- +-from ubuntuone.platform.linux import event_logging +- +- +-class ZeitgeistDetectionTestCase(TestCase): +- """Test the is_zeitgeist_installed function.""" +- +- def patch_module(self, module_name, fake_module): +- """Monkey patch a module for the duration of the test.""" +- UNDEFINED = object() +- real_module = sys.modules.get(module_name, UNDEFINED) +- +- def restore(): +- """Restore the real_module.""" +- if real_module is UNDEFINED: +- del(sys.modules[module_name]) +- else: +- sys.modules[module_name] = real_module +- +- self.addCleanup(restore) +- sys.modules[module_name] = fake_module +- +- def test_zg_installed_returns_true(self): +- """When zg is installed, it returns true.""" +- self.patch_module("zeitgeist", object()) +- self.patch_module("zeitgeist.mimetypes", object()) +- result = event_logging.is_zeitgeist_installed() +- self.assertEqual(result, True) +- +- def test_zg_not_installed_returns_false(self): +- """When zg is not installed, it returns false.""" +- self.patch_module("zeitgeist", None) +- result = event_logging.is_zeitgeist_installed() +- self.assertEqual(result, False) +- +- def test_old_zg_installed_returns_false(self): +- """When an old zg is installed, it returns false.""" +- self.patch_module("zeitgeist", object()) +- self.patch_module("zeitgeist.mimetypes", None) +- result = event_logging.is_zeitgeist_installed() +- self.assertEqual(result, False) +- +- +-class GetListenerTestCase(TestCase): +- """The zg listener is created.""" +- +- def test_zeitgeist_installed_returns_listener(self): +- """get_listener returns a listener if ZG installed.""" +- self.patch(event_logging, "is_zeitgeist_installed", lambda: True) +- listener = event_logging.get_listener(None, None) +- self.assertNotEqual(listener, None) +- +- def test_zeitgeist_not_installed_returns_none(self): +- """get_listener returns None if ZG not installed.""" +- self.patch(event_logging, "is_zeitgeist_installed", lambda: False) +- listener = event_logging.get_listener(None, None) +- self.assertEqual(listener, None) + +=== removed file 'tests/platform/windows/test_event_logging.py' +--- old/tests/platform/windows/test_event_logging.py 2012-04-09 20:07:05 +0000 ++++ new/tests/platform/windows/test_event_logging.py 1970-01-01 00:00:00 +0000 +@@ -1,43 +0,0 @@ +-# tests.platform.windows.test_event_logging +-# +-# Author: Alejandro J. Cura +-# +-# Copyright 2010-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Test the event logging on windows.""" +- +-from twisted.trial import unittest +- +-class GetListenerTestCase(unittest.TestCase): +- """Listener creation tests.""" +- +- def test_never_creates_a_listener(self): +- """The listener is never created on windows.""" +- from ubuntuone.platform.windows import event_logging +- listener = event_logging.get_listener(None, None) +- self.assertEqual(listener, None) +- + +=== modified file 'tests/syncdaemon/test_main.py' +--- old/tests/syncdaemon/test_main.py 2012-04-09 20:07:05 +0000 ++++ new/tests/syncdaemon/test_main.py 2013-08-27 16:33:16 +0000 +@@ -79,8 +79,6 @@ class MainTests(BaseTwistedTestCase): + self.partials_dir = self.mktemp('partials_dir') + + self.patch(main_mod, 'SyncdaemonService', FakedExternalInterface) +- # no event logger by default +- self.patch(main_mod.event_logging, "get_listener", lambda *a: None) + # no status listener by default + self.patch(main_mod.status_listener, "get_listener", lambda *a: None) + +@@ -252,18 +250,6 @@ class MainTests(BaseTwistedTestCase): + s.add(x) + return s + +- def test_event_logger_starts_if_available(self): +- """The event logger is started if available.""" +- self.patch(main_mod.event_logging, +- "get_listener", lambda *a: FakeListener()) +- main = self.build_main() +- self.assertIn(main.eventlog_listener, self._get_listeners(main)) +- +- def test_event_logger_not_started_if_not_available(self): +- """The event logger is not started if it's not available.""" +- main = self.build_main() +- self.assertNotIn(main.eventlog_listener, self._get_listeners(main)) +- + def test_status_listener_is_installed(self): + """The status listener is installed if needed.""" + self.patch(main_mod.status_listener, + +=== modified file 'tests/syncdaemon/test_status_listener.py' +--- old/tests/syncdaemon/test_status_listener.py 2012-04-09 20:07:05 +0000 ++++ new/tests/syncdaemon/test_status_listener.py 2013-08-27 16:33:16 +0000 +@@ -54,12 +54,6 @@ class GetListenerTestCase(BaseTwistedTes + self.assertEqual(listener.vm, vm) + self.assertNotEqual(listener.status_frontend, None) + +- def test_zeitgeist_not_installed_returns_none(self): +- """get_listener returns None if status reporting is disabled.""" +- self.patch(status_listener, "should_start_listener", lambda: False) +- listener = status_listener.get_listener(None, None) +- self.assertEqual(listener, None) +- + + def listen_for(event_q, event, callback, count=1, collect=False): + """Setup a EQ listener for the specified event.""" + +=== removed directory 'ubuntuone/eventlog' +=== removed file 'ubuntuone/eventlog/__init__.py' +--- old/ubuntuone/eventlog/__init__.py 2012-04-09 20:07:05 +0000 ++++ new/ubuntuone/eventlog/__init__.py 1970-01-01 00:00:00 +0000 +@@ -1,29 +0,0 @@ +-# ubuntuone.eventlog - Ubuntu One event logging modules +-# +-# Copyright 2010-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Event logging module.""" + +=== removed file 'ubuntuone/eventlog/zg_listener.py' +--- old/ubuntuone/eventlog/zg_listener.py 2012-04-09 20:07:05 +0000 ++++ new/ubuntuone/eventlog/zg_listener.py 1970-01-01 00:00:00 +0000 +@@ -1,556 +0,0 @@ +-# ubuntuone.eventlog.zg_listener - listen for SD events, log into ZG +-# +-# Author: Alejandro J. Cura +-# +-# Copyright 2010-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Event logging from SyncDaemon into Zeitgeist.""" +- +-import mimetypes +- +-from os.path import basename +- +-from zeitgeist.datamodel import Event, Interpretation, Manifestation, Subject +-from zeitgeist.mimetypes import get_interpretation_for_mimetype +- +-from ubuntuone.eventlog import zglog +-from ubuntuone.syncdaemon.volume_manager import Share, UDF +- +-ACTOR_UBUNTUONE = "dbus://com.ubuntuone.SyncDaemon.service" +-DIRECTORY_MIMETYPE = "inode/directory" +-DEFAULT_MIME = "application/octet-stream" +-DEFAULT_INTERPRETATION = Interpretation.DOCUMENT +-EVENT_INTERPRETATION_U1_FOLDER_SHARED = "u1://FolderShared" +-EVENT_INTERPRETATION_U1_FOLDER_UNSHARED = "u1://FolderUnshared" +-EVENT_INTERPRETATION_U1_SHARE_ACCEPTED = "u1://ShareAccepted" +-EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED = "u1://ShareUnaccepted" +-EVENT_INTERPRETATION_U1_CONFLICT_RENAME = "u1://ConflictRename" +-EVENT_INTERPRETATION_U1_UDF_CREATED = "u1://UserFolderCreated" +-EVENT_INTERPRETATION_U1_UDF_DELETED = "u1://UserFolderDeleted" +-EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED = "u1://UserFolderSubscribed" +-EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED = "u1://UserFolderUnsubscribed" +-MANIFESTATION_U1_CONTACT_DATA_OBJECT = "u1://ContactDataObject" +-INTERPRETATION_U1_CONTACT = "u1://Contact" +-URI_PROTOCOL_U1 = "ubuntuone:" +-STORAGE_LOCAL = "" +-STORAGE_NETWORK = "net" +-STORAGE_DELETED = "deleted" +- +- +-class ZeitgeistListener(object): +- """An Event Queue listener that logs into ZG.""" +- +- def __init__(self, fsm, vm): +- """Initialize this instance.""" +- self.fsm = fsm +- self.vm = vm +- self.zg = zglog.ZeitgeistLogger() +- self.newly_created_server_files = set() +- self.newly_created_local_files = set() +- +- def handle_AQ_CREATE_SHARE_OK(self, share_id, marker): +- """Log the 'directory shared thru the server' event.""" +- share_id = str(share_id) +- share = self.vm.shared.get(share_id) +- if not share: +- share = self.vm.marker_share_map[marker] +- share_id = share.node_id +- self.log_folder_shared(share, share_id) +- +- def handle_AQ_SHARE_INVITATION_SENT(self, marker): +- """Log the 'directory shared thru http' event.""" +- share = self.vm.marker_share_map[marker] +- mdo = self.fsm.get_by_mdid(marker) +- self.log_folder_shared(share, mdo.share_id) +- +- def log_folder_shared(self, share, share_id): +- """Log the 'directory shared' event.""" +- fullpath = share.path +- folder_name = basename(fullpath) +- +- folder = Subject.new_for_values( +- uri=URI_PROTOCOL_U1 + str(share.node_id), +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.REMOTE_DATA_OBJECT, +- origin="file:///" + fullpath, +- text=folder_name, +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_NETWORK) +- +- other_username = share.other_username +- other_user = Subject.new_for_values( +- uri="mailto:" + other_username, +- interpretation=INTERPRETATION_U1_CONTACT, +- text=other_username, +- manifestation=MANIFESTATION_U1_CONTACT_DATA_OBJECT) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_FOLDER_SHARED, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[folder, other_user]) +- +- self.zg.log(event) +- +- def handle_VM_SHARE_DELETED(self, share): +- """Log the share deleted event.""" +- folder = Subject.new_for_values( +- uri=URI_PROTOCOL_U1 + str(share.node_id), +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.REMOTE_DATA_OBJECT, +- origin="file:///" + share.path, +- text=basename(share.path), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_NETWORK) +- +- other_username = share.other_username +- other_user = Subject.new_for_values( +- uri="mailto:" + other_username, +- interpretation=INTERPRETATION_U1_CONTACT, +- text=other_username, +- manifestation=MANIFESTATION_U1_CONTACT_DATA_OBJECT) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_FOLDER_UNSHARED, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[folder, other_user]) +- +- self.zg.log(event) +- +- def handle_VM_SHARE_CREATED(self, share_id): +- """Log the share accepted event.""" +- share = self.vm.shares[share_id] +- +- folder = Subject.new_for_values( +- uri=URI_PROTOCOL_U1 + str(share.node_id), +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.REMOTE_DATA_OBJECT, +- origin="file:///" + share.path, +- text=basename(share.path), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_NETWORK) +- +- other_username = share.other_username +- other_user = Subject.new_for_values( +- uri="mailto:" + other_username, +- interpretation=INTERPRETATION_U1_CONTACT, +- text=other_username, +- manifestation=MANIFESTATION_U1_CONTACT_DATA_OBJECT) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_SHARE_ACCEPTED, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[folder, other_user]) +- +- self.zg.log(event) +- +- def log_share_unaccepted(self, share): +- """Log the share unaccepted event.""" +- folder = Subject.new_for_values( +- uri=URI_PROTOCOL_U1 + str(share.node_id), +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.REMOTE_DATA_OBJECT, +- origin="file:///" + share.path, +- text=basename(share.path), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_NETWORK) +- +- other_username = share.other_username +- other_user = Subject.new_for_values( +- uri="mailto:" + other_username, +- interpretation=INTERPRETATION_U1_CONTACT, +- text=other_username, +- manifestation=MANIFESTATION_U1_CONTACT_DATA_OBJECT) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_SHARE_UNACCEPTED, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[folder, other_user]) +- +- self.zg.log(event) +- +- def log_udf_deleted(self, volume): +- """Log the udf deleted event.""" +- folder = Subject.new_for_values( +- uri=URI_PROTOCOL_U1 + str(volume.node_id), +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.DELETED_RESOURCE, +- origin="file:///" + volume.path, +- text=basename(volume.path), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_DELETED) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_UDF_DELETED, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[folder]) +- +- self.zg.log(event) +- +- def handle_VM_VOLUME_DELETED(self, volume): +- """Log the share/UDF unaccepted event.""" +- if isinstance(volume, Share): +- self.log_share_unaccepted(volume) +- if isinstance(volume, UDF): +- self.log_udf_deleted(volume) +- +- def handle_VM_UDF_CREATED(self, udf): +- """An udf was created. Log it into Zeitgeist.""" +- folder = Subject.new_for_values( +- uri=URI_PROTOCOL_U1 + str(udf.node_id), +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.REMOTE_DATA_OBJECT, +- origin="file:///" + udf.path, +- text=basename(udf.path), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_NETWORK) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_UDF_CREATED, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[folder]) +- +- self.zg.log(event) +- +- def handle_VM_UDF_SUBSCRIBED(self, udf): +- """An udf was subscribed.""" +- +- folder = Subject.new_for_values( +- uri="file:///" + udf.path, +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.FILE_DATA_OBJECT, +- origin=URI_PROTOCOL_U1 + str(udf.node_id), +- text=basename(udf.path), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_LOCAL) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_UDF_SUBSCRIBED, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[folder]) +- +- self.zg.log(event) +- +- def handle_VM_UDF_UNSUBSCRIBED(self, udf): +- """An udf was unsubscribed.""" +- +- folder = Subject.new_for_values( +- uri="file:///" + udf.path, +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.DELETED_RESOURCE, +- origin=URI_PROTOCOL_U1 + str(udf.node_id), +- text=basename(udf.path), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_DELETED) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_UDF_UNSUBSCRIBED, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[folder]) +- +- self.zg.log(event) +- +- def handle_AQ_FILE_NEW_OK(self, volume_id, marker, new_id, new_generation): +- """A new file was created on server. Store and wait till it uploads.""" +- self.newly_created_server_files.add((volume_id, new_id)) +- +- def get_mime_and_interpretation_for_filepath(self, filepath): +- """Try to guess the mime and the interpretation from the path.""" +- mime, encoding = mimetypes.guess_type(filepath) +- if mime is None: +- return DEFAULT_MIME, DEFAULT_INTERPRETATION +- interpret = get_interpretation_for_mimetype(mime) +- if interpret is None: +- return DEFAULT_MIME, Interpretation.DOCUMENT +- return mime, interpret +- +- def handle_AQ_UPLOAD_FINISHED(self, share_id, node_id, hash, +- new_generation): +- """A file finished uploading to the server.""" +- +- mdo = self.fsm.get_by_node_id(share_id, node_id) +- path = self.fsm.get_abspath(share_id, mdo.path) +- +- if (share_id, node_id) in self.newly_created_server_files: +- self.newly_created_server_files.remove((share_id, node_id)) +- event_interpretation = Interpretation.CREATE_EVENT +- else: +- event_interpretation = Interpretation.MODIFY_EVENT +- +- mime, interp = self.get_mime_and_interpretation_for_filepath(path) +- +- file_subject = Subject.new_for_values( +- uri=URI_PROTOCOL_U1 + str(node_id), +- interpretation=interp, +- manifestation=Manifestation.REMOTE_DATA_OBJECT, +- origin="file:///" + path, +- text=basename(path), +- mimetype=mime, +- storage=STORAGE_NETWORK) +- +- event = Event.new_for_values( +- interpretation=event_interpretation, +- manifestation=Manifestation.SCHEDULED_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[file_subject]) +- +- self.zg.log(event) +- +- def handle_AQ_DIR_NEW_OK(self, volume_id, marker, new_id, new_generation): +- """A dir was created on the server.""" +- +- mdo = self.fsm.get_by_node_id(volume_id, new_id) +- path = self.fsm.get_abspath(volume_id, mdo.path) +- +- file_subject = Subject.new_for_values( +- uri=URI_PROTOCOL_U1 + str(new_id), +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.REMOTE_DATA_OBJECT, +- origin="file:///" + path, +- text=basename(path), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_NETWORK) +- +- event = Event.new_for_values( +- interpretation=Interpretation.CREATE_EVENT, +- manifestation=Manifestation.SCHEDULED_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[file_subject]) +- +- self.zg.log(event) +- +- def handle_SV_FILE_NEW(self, volume_id, node_id, parent_id, name): +- """A file was created locally by Syncdaemon.""" +- self.newly_created_local_files.add((volume_id, node_id)) +- +- def handle_AQ_DOWNLOAD_FINISHED(self, share_id, node_id, server_hash): +- """A file finished downloading from the server.""" +- +- mdo = self.fsm.get_by_node_id(share_id, node_id) +- path = self.fsm.get_abspath(share_id, mdo.path) +- +- if (share_id, node_id) in self.newly_created_local_files: +- self.newly_created_local_files.remove((share_id, node_id)) +- event_interpretation = Interpretation.CREATE_EVENT +- else: +- event_interpretation = Interpretation.MODIFY_EVENT +- +- mime, interp = self.get_mime_and_interpretation_for_filepath(path) +- +- file_subject = Subject.new_for_values( +- uri="file:///" + path, +- interpretation=interp, +- manifestation=Manifestation.FILE_DATA_OBJECT, +- origin=URI_PROTOCOL_U1 + str(node_id), +- text=basename(path), +- mimetype=mime, +- storage=STORAGE_LOCAL) +- +- event = Event.new_for_values( +- interpretation=event_interpretation, +- manifestation=Manifestation.WORLD_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[file_subject]) +- +- self.zg.log(event) +- +- def handle_SV_DIR_NEW(self, volume_id, node_id, parent_id, name): +- """A file finished downloading from the server.""" +- +- mdo = self.fsm.get_by_node_id(volume_id, node_id) +- path = self.fsm.get_abspath(volume_id, mdo.path) +- +- file_subject = Subject.new_for_values( +- uri="file:///" + path, +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.FILE_DATA_OBJECT, +- origin=URI_PROTOCOL_U1 + str(node_id), +- text=basename(path), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_LOCAL) +- +- event = Event.new_for_values( +- interpretation=Interpretation.CREATE_EVENT, +- manifestation=Manifestation.WORLD_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[file_subject]) +- +- self.zg.log(event) +- +- def handle_SV_FILE_DELETED(self, volume_id, node_id, was_dir, old_path): +- """A file or folder was deleted locally by Syncdaemon.""" +- if was_dir: +- mime, interp = DIRECTORY_MIMETYPE, Interpretation.FOLDER +- else: +- mime, interp = self.get_mime_and_interpretation_for_filepath( +- old_path) +- +- file_subject = Subject.new_for_values( +- uri="file:///" + old_path, +- interpretation=interp, +- manifestation=Manifestation.DELETED_RESOURCE, +- origin=URI_PROTOCOL_U1 + str(node_id), +- text=basename(old_path), +- mimetype=mime, +- storage=STORAGE_DELETED) +- +- event = Event.new_for_values( +- interpretation=Interpretation.DELETE_EVENT, +- manifestation=Manifestation.WORLD_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[file_subject]) +- +- self.zg.log(event) +- +- def handle_AQ_UNLINK_OK(self, share_id, parent_id, node_id, +- new_generation, was_dir, old_path): +- """A file or folder was deleted on the server by Syncdaemon,""" +- if was_dir: +- mime, interp = DIRECTORY_MIMETYPE, Interpretation.FOLDER +- else: +- mime, interp = self.get_mime_and_interpretation_for_filepath( +- old_path) +- +- file_subject = Subject.new_for_values( +- uri=URI_PROTOCOL_U1 + str(node_id), +- interpretation=interp, +- manifestation=Manifestation.DELETED_RESOURCE, +- origin="file:///" + old_path, +- text=basename(old_path), +- mimetype=mime, +- storage=STORAGE_DELETED) +- +- event = Event.new_for_values( +- interpretation=Interpretation.DELETE_EVENT, +- manifestation=Manifestation.SCHEDULED_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[file_subject]) +- +- self.zg.log(event) +- +- def handle_FSM_FILE_CONFLICT(self, old_name, new_name): +- """A file was renamed because of conflict.""" +- mime, interp = self.get_mime_and_interpretation_for_filepath(old_name) +- +- file_subject = Subject.new_for_values( +- uri="file:///" + new_name, +- interpretation=interp, +- manifestation=Manifestation.FILE_DATA_OBJECT, +- origin="file:///" + old_name, +- text=basename(new_name), +- mimetype=mime, +- storage=STORAGE_LOCAL) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_CONFLICT_RENAME, +- manifestation=Manifestation.WORLD_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[file_subject]) +- +- self.zg.log(event) +- +- def handle_FSM_DIR_CONFLICT(self, old_name, new_name): +- """A dir was renamed because of conflict.""" +- folder_subject = Subject.new_for_values( +- uri="file:///" + new_name, +- interpretation=Interpretation.FOLDER, +- manifestation=Manifestation.FILE_DATA_OBJECT, +- origin="file:///" + old_name, +- text=basename(new_name), +- mimetype=DIRECTORY_MIMETYPE, +- storage=STORAGE_LOCAL) +- +- event = Event.new_for_values( +- interpretation=EVENT_INTERPRETATION_U1_CONFLICT_RENAME, +- manifestation=Manifestation.WORLD_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[folder_subject]) +- +- self.zg.log(event) +- +- def handle_AQ_CHANGE_PUBLIC_ACCESS_OK(self, share_id, node_id, is_public, +- public_url): +- """The status of a published resource changed. Log it!""" +- if is_public: +- self.log_publishing(share_id, node_id, is_public, public_url) +- else: +- self.log_unpublishing(share_id, node_id, is_public, public_url) +- +- def log_publishing(self, share_id, node_id, is_public, public_url): +- """Log the publishing of a resource.""" +- mime, interp = self.get_mime_and_interpretation_for_filepath( +- public_url) +- +- origin = "" if node_id is None else URI_PROTOCOL_U1 + str(node_id) +- +- public_file = Subject.new_for_values( +- uri=public_url, +- interpretation=interp, +- manifestation=Manifestation.REMOTE_DATA_OBJECT, +- origin=origin, +- text=public_url, +- mimetype=mime, +- storage=STORAGE_NETWORK) +- +- event = Event.new_for_values( +- interpretation=Interpretation.CREATE_EVENT, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[public_file]) +- +- self.zg.log(event) +- +- def log_unpublishing(self, share_id, node_id, is_public, public_url): +- """Log the unpublishing of a resource.""" +- mime, interp = self.get_mime_and_interpretation_for_filepath( +- public_url) +- +- origin = "" if node_id is None else URI_PROTOCOL_U1 + str(node_id) +- +- public_file = Subject.new_for_values( +- uri=public_url, +- interpretation=interp, +- manifestation=Manifestation.DELETED_RESOURCE, +- text=public_url, +- origin=origin, +- mimetype=mime, +- storage=STORAGE_DELETED) +- +- event = Event.new_for_values( +- interpretation=Interpretation.DELETE_EVENT, +- manifestation=Manifestation.USER_ACTIVITY, +- actor=ACTOR_UBUNTUONE, +- subjects=[public_file]) +- +- self.zg.log(event) + +=== removed file 'ubuntuone/eventlog/zglog.py' +--- old/ubuntuone/eventlog/zglog.py 2012-04-09 20:07:05 +0000 ++++ new/ubuntuone/eventlog/zglog.py 1970-01-01 00:00:00 +0000 +@@ -1,61 +0,0 @@ +-# -*- coding: utf-8 -*- +-# +-# Author: Alejandro J. Cura +-# +-# Copyright 2010-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Log into the Zeitgeist daemon.""" +- +-from twisted.internet.defer import Deferred +- +-from ubuntuone.logger import logging +- +-logger = logging.getLogger('ubuntuone.eventlog.zglog') +- +- +-class ZeitgeistLogger(object): +- """A class that logs zeitgeist events.""" +- client = None +- +- def __init__(self): +- """Initialize this instance.""" +- try: +- from zeitgeist.client import ZeitgeistClient +- self.client = ZeitgeistClient() +- logger.info("Zeitgeist support initialized.") +- except Exception: +- logger.exception("Zeitgeist support not started:") +- +- def log(self, event): +- """Log a zeitgeist event.""" +- d = Deferred() +- if self.client: +- logger.info("Logging Zeitgeist event: %r", event) +- self.client.insert_event(event, d.callback, d.errback) +- else: +- d.callback([]) +- return d + +=== removed file 'ubuntuone/platform/event_logging.py' +--- old/ubuntuone/platform/event_logging.py 2012-04-09 20:07:05 +0000 ++++ new/ubuntuone/platform/event_logging.py 1970-01-01 00:00:00 +0000 +@@ -1,42 +0,0 @@ +-# -*- coding: utf-8 *-* +-# +-# Copyright 2011-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Builds a syncdaemon listener that logs events if ZG is installed.""" +- +-import sys +- +- +-if sys.platform == "win32": +- from ubuntuone.platform.windows import event_logging +- source = event_logging +-else: +- from ubuntuone.platform.linux import event_logging +- source = event_logging +- is_zeitgeist_installed = source.is_zeitgeist_installed +- +-get_listener = source.get_listener + +=== removed file 'ubuntuone/platform/linux/event_logging.py' +--- old/ubuntuone/platform/linux/event_logging.py 2012-04-09 20:07:05 +0000 ++++ new/ubuntuone/platform/linux/event_logging.py 1970-01-01 00:00:00 +0000 +@@ -1,52 +0,0 @@ +-# ubuntuone.platform.linux.event_logging +-# +-# Author: Alejandro J. Cura +-# +-# Copyright 2010-2012 Canonical Ltd. +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of the GNU General Public License version 3, as published +-# by the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +-# PURPOSE. See the GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program. If not, see . +-# +-# In addition, as a special exception, the copyright holders give +-# permission to link the code of portions of this program with the +-# OpenSSL library under certain conditions as described in each +-# individual source file, and distribute linked combinations +-# including the two. +-# You must obey the GNU General Public License in all respects +-# for all of the code used other than OpenSSL. If you modify +-# file(s) with this exception, you may extend this exception to your +-# version of the file(s), but you are not obligated to do so. If you +-# do not wish to do so, delete this exception statement from your +-# version. If you delete this exception statement from all source +-# files in the program, then also delete it here. +-"""Builds a syncdaemon listener that logs events if ZG is installed.""" +- +- +-def is_zeitgeist_installed(): +- """Return true if zeitgeist is installed.""" +- try: +- import zeitgeist +- import zeitgeist.mimetypes +- # use the above module in some way so pylint does not complain +- assert(zeitgeist is not None) +- return True +- except (ImportError, AttributeError): +- return False +- +- +-def get_listener(fsm, vm): +- """Build a listener if zg is installed.""" +- if is_zeitgeist_installed(): +- from ubuntuone.eventlog import zg_listener +- return zg_listener.ZeitgeistListener(fsm, vm) +- else: +- return None + +=== modified file 'ubuntuone/syncdaemon/main.py' +--- old/ubuntuone/syncdaemon/main.py 2012-04-09 20:08:42 +0000 ++++ new/ubuntuone/syncdaemon/main.py 2013-08-27 16:33:16 +0000 +@@ -48,7 +48,6 @@ from ubuntuone.syncdaemon import ( + volume_manager, + ) + from ubuntuone import syncdaemon, clientdefs +-from ubuntuone.platform import event_logging + from ubuntuone.syncdaemon import status_listener + from ubuntuone.syncdaemon.interaction_interfaces import SyncdaemonService + from ubuntuone.syncdaemon.states import StateManager, QueueManager +@@ -145,22 +144,12 @@ class Main(object): + if user_config.get_autoconnect(): + self.external.connect(autoconnecting=True) + +- self.eventlog_listener = None +- self.start_event_logger() +- + self.status_listener = None + self.start_status_listener() + + self.mark = task.LoopingCall(self.log_mark) + self.mark.start(mark_interval) + +- def start_event_logger(self): +- """Start the event logger if it's available for this platform.""" +- self.eventlog_listener = event_logging.get_listener(self.fs, self.vm) +- # subscribe to EQ, to be unsubscribed in shutdown +- if self.eventlog_listener: +- self.event_q.subscribe(self.eventlog_listener) +- + def start_status_listener(self): + """Start the status listener if it is configured to start.""" + self.status_listener = status_listener.get_listener(self.fs, self.vm) +@@ -224,8 +213,6 @@ class Main(object): + self.event_q.push('SYS_QUIT') + + self.event_q.unsubscribe(self.vm) +- if getattr(self, 'eventlog_listener', None) is not None: +- self.event_q.unsubscribe(self.eventlog_listener) + if getattr(self, 'status_listener', None) is not None: + self.event_q.unsubscribe(self.status_listener) + + diff -Nru ubuntuone-client-3.0.0/debian/patches/02_bzr-ensure-content-type.patch ubuntuone-client-3.0.2/debian/patches/02_bzr-ensure-content-type.patch --- ubuntuone-client-3.0.0/debian/patches/02_bzr-ensure-content-type.patch 1970-01-01 00:00:00.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/patches/02_bzr-ensure-content-type.patch 2014-04-10 21:13:53.000000000 +0000 @@ -0,0 +1,30 @@ +=== modified file 'ubuntuone/syncdaemon/action_queue.py' +--- old/ubuntuone/syncdaemon/action_queue.py 2012-06-14 19:30:53 +0000 ++++ new/ubuntuone/syncdaemon/action_queue.py 2013-08-30 20:44:27 +0000 +@@ -2155,8 +2155,11 @@ class ChangePublicAccess(ActionQueueComm + iri = u"https://one.ubuntu.com/files/api/set_public/%s" % (node_key,) + data = dict(is_public=bool(self.is_public)) + pdata = urlencode(data) ++ ++ extra_headers = {'Content-Type': 'application/x-www-form-urlencoded'} + response = yield self.action_queue.webcall(iri, method="POST", +- post_content=pdata) ++ post_content=pdata, ++ extra_headers=extra_headers) + defer.returnValue(simplejson.loads(response.content)) + + def _run(self): + +=== modified file 'ubuntuone/syncdaemon/interaction_interfaces.py' +--- old/ubuntuone/syncdaemon/interaction_interfaces.py 2012-04-09 20:07:05 +0000 ++++ new/ubuntuone/syncdaemon/interaction_interfaces.py 2013-08-30 13:59:40 +0000 +@@ -1063,6 +1063,8 @@ class SyncdaemonEventListener(Syncdaemon + def handle_AQ_CHANGE_PUBLIC_ACCESS_OK(self, share_id, node_id, + is_public, public_url): + """Handle the AQ_CHANGE_PUBLIC_ACCESS_OK event.""" ++ if public_url is None: ++ public_url = '' + if share_id is None: + share_id = '' + share_id = str(share_id) + diff -Nru ubuntuone-client-3.0.0/debian/patches/CVE-2011-4409.patch ubuntuone-client-3.0.2/debian/patches/CVE-2011-4409.patch --- ubuntuone-client-3.0.0/debian/patches/CVE-2011-4409.patch 2012-05-29 18:12:00.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/patches/CVE-2011-4409.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -Description: fix MITM via incorrect ssl cert validation -Origin: https://bugs.launchpad.net/ubuntu/+source/ubuntuone-client/+bug/882062 -Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ubuntuone-client/+bug/882062 - -Index: ubuntuone-client-3.0.0/data/syncdaemon.conf -=================================================================== ---- ubuntuone-client-3.0.0.orig/data/syncdaemon.conf 2012-03-07 09:43:51.000000000 -0500 -+++ ubuntuone-client-3.0.0/data/syncdaemon.conf 2012-05-29 14:07:45.258572463 -0400 -@@ -2,7 +2,7 @@ - host.default = fs-1.one.ubuntu.com - host.help = The server address - --dns_srv.default = _https._tcp.fs.ubuntuone.com -+dns_srv.default = _https._tcp.fs.one.ubuntu.com - dns_srv.help = The DNS SRV record - - disable_ssl_verify.default = False -Index: ubuntuone-client-3.0.0/ubuntuone/syncdaemon/action_queue.py -=================================================================== ---- ubuntuone-client-3.0.0.orig/ubuntuone/syncdaemon/action_queue.py 2012-04-11 11:09:28.000000000 -0400 -+++ ubuntuone-client-3.0.0/ubuntuone/syncdaemon/action_queue.py 2012-05-29 14:07:45.298572462 -0400 -@@ -855,7 +855,7 @@ - def _make_connection(self, result): - """Do the real connect call.""" - host, port = result -- ssl_context = get_ssl_context(self.disable_ssl_verify) -+ ssl_context = get_ssl_context(self.disable_ssl_verify, host) - client = yield self.tunnel_runner.get_client() - if self.use_ssl: - self.connector = client.connectSSL(host, port, factory=self, diff -Nru ubuntuone-client-3.0.0/debian/patches/series ubuntuone-client-3.0.2/debian/patches/series --- ubuntuone-client-3.0.0/debian/patches/series 2012-05-29 18:06:49.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/patches/series 2014-04-10 21:14:43.000000000 +0000 @@ -1 +1,4 @@ -CVE-2011-4409.patch +00_bzr1259_lp1013401_reupload.patch +01_bzr1384_remove_zg.patch +02_bzr-ensure-content-type.patch +00_farewell-u1.patch diff -Nru ubuntuone-client-3.0.0/debian/python-ubuntuone-client.install ubuntuone-client-3.0.2/debian/python-ubuntuone-client.install --- ubuntuone-client-3.0.0/debian/python-ubuntuone-client.install 2012-04-11 17:14:31.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/python-ubuntuone-client.install 2014-04-10 21:13:53.000000000 +0000 @@ -5,6 +5,5 @@ debian/tmp/usr/lib/python2.*/*-packages/ubuntuone-client/ubuntuone/*.py debian/tmp/usr/lib/python2.*/*-packages/ubuntuone-client/ubuntuone/platform debian/tmp/usr/lib/python2.*/*-packages/ubuntuone-client/ubuntuone/status -debian/tmp/usr/lib/python2.*/*-packages/ubuntuone-client/ubuntuone/eventlog debian/tmp/usr/lib/python2.*/*-packages/ubuntuone-client/ubuntuone/syncdaemon diff -Nru ubuntuone-client-3.0.0/debian/watch ubuntuone-client-3.0.2/debian/watch --- ubuntuone-client-3.0.0/debian/watch 2012-04-11 19:11:29.000000000 +0000 +++ ubuntuone-client-3.0.2/debian/watch 2014-04-10 21:13:53.000000000 +0000 @@ -1,3 +1,3 @@ version=3 -http://launchpad.net/ubuntuone-client/stable-3-0/3.0.0 .*/ubuntuone-client-([0-9.]+)\.tar\.gz +https://launchpad.net/ubuntuone-client/stable-3-0 .*/ubuntuone-client-([0-9.]+)\.tar\.gz diff -Nru ubuntuone-client-3.0.0/docs/reference/html/ch01.html ubuntuone-client-3.0.2/docs/reference/html/ch01.html --- ubuntuone-client-3.0.0/docs/reference/html/ch01.html 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/html/ch01.html 2012-06-14 20:48:27.000000000 +0000 @@ -21,7 +21,7 @@

-[Insert title here]

+[Insert title here]
SyncdaemonMetadata diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/libsyncdaemon.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/libsyncdaemon.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/libsyncdaemon.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/libsyncdaemon.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-authentication.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-authentication.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-authentication.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-authentication.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-config-interface.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-config-interface.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-config-interface.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-config-interface.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-credentials.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-credentials.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-credentials.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-credentials.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-daemon.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-daemon.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-daemon.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-daemon.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-events-interface.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-events-interface.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-events-interface.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-events-interface.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-file-info.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-file-info.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-file-info.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-file-info.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-filesystem-interface.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-filesystem-interface.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-filesystem-interface.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-filesystem-interface.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-folder-info.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-folder-info.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-folder-info.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-folder-info.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-folders-interface.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-folders-interface.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-folders-interface.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-folders-interface.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-interface.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-interface.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-interface.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-interface.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-marshal.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-marshal.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-marshal.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-marshal.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-metadata.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-metadata.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-metadata.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-metadata.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-publicfiles-interface.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-publicfiles-interface.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-publicfiles-interface.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-publicfiles-interface.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-share-info.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-share-info.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-share-info.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-share-info.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-shares-interface.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-shares-interface.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-shares-interface.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-shares-interface.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-status-info.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-status-info.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-status-info.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-status-info.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-status-interface.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-status-interface.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-status-interface.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-status-interface.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-transfer-info.sgml ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-transfer-info.sgml --- ubuntuone-client-3.0.0/docs/reference/tmpl/syncdaemon-transfer-info.sgml 2012-04-11 15:11:47.000000000 +0000 +++ ubuntuone-client-3.0.2/docs/reference/tmpl/syncdaemon-transfer-info.sgml 2012-06-14 20:48:27.000000000 +0000 @@ -9,11 +9,13 @@ + + diff -Nru ubuntuone-client-3.0.0/libsyncdaemon/syncdaemon-daemon.c ubuntuone-client-3.0.2/libsyncdaemon/syncdaemon-daemon.c --- ubuntuone-client-3.0.0/libsyncdaemon/syncdaemon-daemon.c 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/libsyncdaemon/syncdaemon-daemon.c 2012-06-14 20:17:10.000000000 +0000 @@ -963,6 +963,7 @@ g_free (dirpath); return FALSE; } + g_free (dirpath); /* And finally check UDFs */ interface = syncdaemon_daemon_get_folders_interface (daemon); diff -Nru ubuntuone-client-3.0.0/Makefile.am ubuntuone-client-3.0.2/Makefile.am --- ubuntuone-client-3.0.0/Makefile.am 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/Makefile.am 2012-06-14 20:17:10.000000000 +0000 @@ -54,8 +54,8 @@ test: logging.conf $(clientdefs_DATA) Makefile echo "$(PYTHONPATH)" if test "x$(builddir)" == "x$(srcdir)"; then \ - PYTHONPATH="$(PYTHONPATH)" u1trial -r $(REACTOR) -p tests/platform/windows,tests/proxy tests; \ - PYTHONPATH="$(PYTHONPATH)" u1trial -r qt4 -p tests/platform/windows tests/proxy; \ + PYTHONPATH="$(PYTHONPATH)" u1trial -r $(REACTOR) -p tests/platform/windows,tests/proxy tests || exit 1; \ + PYTHONPATH="$(PYTHONPATH)" u1trial -r qt4 -p tests/platform/windows tests/proxy || exit 1; \ fi rm -rf _trial_temp diff -Nru ubuntuone-client-3.0.0/Makefile.in ubuntuone-client-3.0.2/Makefile.in --- ubuntuone-client-3.0.0/Makefile.in 2012-04-11 15:10:52.000000000 +0000 +++ ubuntuone-client-3.0.2/Makefile.in 2012-06-14 20:48:17.000000000 +0000 @@ -1016,8 +1016,8 @@ test: logging.conf $(clientdefs_DATA) Makefile echo "$(PYTHONPATH)" if test "x$(builddir)" == "x$(srcdir)"; then \ - PYTHONPATH="$(PYTHONPATH)" u1trial -r $(REACTOR) -p tests/platform/windows,tests/proxy tests; \ - PYTHONPATH="$(PYTHONPATH)" u1trial -r qt4 -p tests/platform/windows tests/proxy; \ + PYTHONPATH="$(PYTHONPATH)" u1trial -r $(REACTOR) -p tests/platform/windows,tests/proxy tests || exit 1; \ + PYTHONPATH="$(PYTHONPATH)" u1trial -r qt4 -p tests/platform/windows tests/proxy || exit 1; \ fi rm -rf _trial_temp Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/__init__.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/__init__.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/eventlog/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/eventlog/__init__.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/eventlog/test_zg_listener.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/eventlog/test_zg_listener.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/eventlog/test_zglog.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/eventlog/test_zglog.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/__init__.pyc differ diff -Nru ubuntuone-client-3.0.0/tests/platform/linux/test_credentials.py ubuntuone-client-3.0.2/tests/platform/linux/test_credentials.py --- ubuntuone-client-3.0.0/tests/platform/linux/test_credentials.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/tests/platform/linux/test_credentials.py 2012-06-14 20:17:10.000000000 +0000 @@ -402,6 +402,32 @@ self.assertEqual(self.sso_server._args, params) +class DictSignatureTestCase(DBusTestCase): + """Test the errors with dict signatures.""" + + def verify(self, app_name, options_dict, reply_handler, error_handler): + """Verify that the options_dict is a dbus.Dictionary.""" + self.assertIsInstance(options_dict, dbus.Dictionary) + + def test_find_credentials_dict_signature(self): + """Test for find_credentials.""" + creds_man = CredentialsManagement() + self.patch(creds_man.sso_proxy, "find_credentials", self.verify) + creds_man.find_credentials() + + def test_find_credentials_sync_dict_signature(self): + """Test for find_credentials_sync.""" + creds_man = CredentialsManagement() + self.patch(creds_man.sso_proxy, "find_credentials_sync", self.verify) + creds_man.find_credentials_sync() + + def test_clear_credentials_dict_signature(self): + """Test for clear_credentials.""" + creds_man = CredentialsManagement() + self.patch(creds_man.sso_proxy, "clear_credentials", self.verify) + creds_man.clear_credentials() + + class SameAppNoErrorTestCase(CredentialsManagementTestCase): """Test case when the app_name matches APP_NAME and there was no error.""" Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_credentials.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_credentials.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_dbus.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_dbus.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_event_logging.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_event_logging.pyc differ diff -Nru ubuntuone-client-3.0.0/tests/platform/linux/test_filesystem_notifications.py ubuntuone-client-3.0.2/tests/platform/linux/test_filesystem_notifications.py --- ubuntuone-client-3.0.0/tests/platform/linux/test_filesystem_notifications.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/tests/platform/linux/test_filesystem_notifications.py 2012-06-14 20:17:10.000000000 +0000 @@ -34,6 +34,7 @@ import os from twisted.internet import defer, reactor +from twisted.trial.unittest import TestCase as PlainTestCase from ubuntuone.syncdaemon import ( event_queue, @@ -434,3 +435,43 @@ self.monitor.rm_watch(path_ancestor) self.assertEqual(self.monitor._general_watchs, {}) self.assertEqual(self.monitor._ancestors_watchs, {}) + + +class FakeEvent(object): + """A fake event.""" + + mask = 0 + name = "" + + +class ECryptFsTestCase(PlainTestCase): + """Tests for the eCryptFS weirdness.""" + + def test_close_write_on_folders_is_ignored(self): + """When eCryptFS sends CLOSE_WRITE on folders, ignore it""" + result = [] + monitor = None + processor = filesystem_notifications._GeneralINotifyProcessor(monitor) + self.patch(processor.general_processor, "push_event", result.append) + + fake_event = FakeEvent() + fake_event.mask = filesystem_notifications.pyinotify.IN_ISDIR + fake_event.name = "/fake/directory/path" + processor.process_IN_CLOSE_WRITE(fake_event) + + self.assertNotIn(fake_event, result) + + + def test_close_write_on_files_is_handled(self): + """When anything sends CLOSE_WRITE on files, handle it.""" + result = [] + monitor = None + processor = filesystem_notifications._GeneralINotifyProcessor(monitor) + self.patch(processor.general_processor, "push_event", result.append) + + fake_event = FakeEvent() + fake_event.mask = filesystem_notifications.pyinotify.IN_CLOSE_WRITE + fake_event.name = "/fake/directory/path" + processor.process_IN_CLOSE_WRITE(fake_event) + + self.assertIn(fake_event, result) Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_filesystem_notifications.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_filesystem_notifications.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_messaging.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_messaging.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_notification.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_notification.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_os_helper.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_os_helper.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_session.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_session.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_unity.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_unity.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/linux/test_vm.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/linux/test_vm.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/test_credentials.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/test_credentials.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/test_external_interface.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/test_external_interface.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/test_filesystem_notifications.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/test_filesystem_notifications.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/test_os_helper.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/test_os_helper.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/test_platform.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/test_platform.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/test_tools.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/test_tools.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/test_u1sdtool.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/test_u1sdtool.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/platform/test_xdg_base_directory.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/platform/test_xdg_base_directory.pyc differ diff -Nru ubuntuone-client-3.0.0/tests/platform/windows/test_os_helper.py ubuntuone-client-3.0.2/tests/platform/windows/test_os_helper.py --- ubuntuone-client-3.0.0/tests/platform/windows/test_os_helper.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/tests/platform/windows/test_os_helper.py 2012-06-14 20:17:10.000000000 +0000 @@ -32,7 +32,6 @@ import os import shutil import sys -import platform from twisted.internet import defer from twisted.trial.unittest import TestCase @@ -482,19 +481,10 @@ class TestIsRoot(TestCase): - """Tests for the is_root function.""" - def test_isanadmin_called(self): - """Test that shell.IsUserAnAdmin is called.""" - expected = object() - self.patch(os_helper.shell, 'IsUserAnAdmin', lambda: expected) - actual = os_helper.is_root() - self.assertEqual(expected, actual) - - def test_is_root_on_xp(self): - """Test that os_helper.is_root always returns False on XP""" + def test_is_root(self): + """Test that os_helper.is_root always returns False""" expected = False - self.patch(platform, "version", "5.1.2600") actual = os_helper.is_root() self.assertEqual(expected, actual) diff -Nru ubuntuone-client-3.0.0/tests/platform/windows/test_tools.py ubuntuone-client-3.0.2/tests/platform/windows/test_tools.py --- ubuntuone-client-3.0.0/tests/platform/windows/test_tools.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/tests/platform/windows/test_tools.py 2012-06-14 20:17:10.000000000 +0000 @@ -29,6 +29,7 @@ """Tests for some tools for talking to the syncdaemon.""" import sys +import operator from twisted.internet import defer from twisted.trial.unittest import TestCase @@ -50,6 +51,7 @@ yield super(TestSyncDaemonTool, self).setUp() self.patch(windows.UbuntuOneClient, "connect", lambda _: defer.Deferred()) self.sdtool = windows.SyncDaemonToolProxy() + self.calls = {} def test_call_after_connection(self): """Test the _call_after_connection method.""" @@ -61,6 +63,31 @@ self.sdtool.connected.callback("got connected!") self.assertEqual(len(collected_calls), 1) + def test_call_after_connection_connect(self): + """Test execute connect in _call_after_connection method.""" + self.patch(self.sdtool.client, "is_connected", lambda: False) + my_connect = lambda *args, **kwargs: operator.setitem( + self.calls, "connect", (args, kwargs)) + self.patch(self.sdtool.client, "connect", my_connect) + collected_calls = [] + test_method = lambda *args: collected_calls.append(args) + test_method = self.sdtool._call_after_connection(test_method) + test_method(123) + self.assertIn("connect", self.calls) + self.assertEqual(self.calls["connect"], ((), {})) + + def test_call_after_connection_not_connect(self): + """Test execute connect in _call_after_connection method.""" + self.patch(self.sdtool.client, "is_connected", lambda: True) + my_connect = lambda *args, **kwargs: operator.setitem( + self.calls, "connect", (args, kwargs)) + self.patch(self.sdtool.client, "connect", my_connect) + collected_calls = [] + test_method = lambda *args: collected_calls.append(args) + test_method = self.sdtool._call_after_connection(test_method) + test_method(123) + self.assertNotIn("connect", self.calls) + def test_should_wrap(self): """Only some attributes should be wrapped.""" test_function = "sample_function" Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/proxy/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/proxy/__init__.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/status/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/status/__init__.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/status/test_aggregator.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/status/test_aggregator.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/fsm/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/fsm/__init__.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/fsm/test_fsm.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/fsm/test_fsm.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/fsm/test_fsm_run.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/fsm/test_fsm_run.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/fsm/test_run_hello.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/fsm/test_run_hello.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/__init__.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/__init__.pyc differ diff -Nru ubuntuone-client-3.0.0/tests/syncdaemon/test_action_queue.py ubuntuone-client-3.0.2/tests/syncdaemon/test_action_queue.py --- ubuntuone-client-3.0.0/tests/syncdaemon/test_action_queue.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/tests/syncdaemon/test_action_queue.py 2012-06-14 20:17:10.000000000 +0000 @@ -31,6 +31,7 @@ from __future__ import with_statement import base64 +import collections import inspect import logging import operator @@ -120,6 +121,26 @@ return self.check(logger.NOTE, *msgs) +class FakeOffloadQueue(object): + """Fake replacemente for offload_queue.""" + def __init__(self): + self.queue = collections.deque() + + def push(self, item): + """Push it.""" + self.queue.append(item) + + def pop(self): + """Pop it.""" + return self.queue.popleft() + + def __len__(self): + return len(self.queue) + + def __getitem__(self, idx): + return self.queue[idx] + + class FakeMagicHash(object): """Fake magic hash.""" _magic_hash = '666' @@ -308,6 +329,8 @@ class BasicTests(BasicTestCase): """Basic tests to check ActionQueue.""" + fake_host = "fake_host" + fake_iri = u"http://%s/" % fake_host def test_implements_interface(self): """Verify ActionQueue and FakeActionQueue interface.""" @@ -412,19 +435,54 @@ self.assertEqual(set(defined_args[1:]), set(evtargs)) @defer.inlineCallbacks - def test_get_webclient(self): - """The webclient is created if it does not exist.""" - self.assertEqual(self.action_queue.webclient, None) - webclient = yield self.action_queue.get_webclient() - self.assertNotEqual(webclient, None) + def test_get_webclient_called_with_iri(self): + """The call to get_webclient includes the iri.""" + called_args = [] + real_get_webclient = action_queue.ActionQueue.get_webclient + + def fake_get_webclient(aq, *args): + """A fake get_webclient.""" + called_args.append(args) + return real_get_webclient(aq, *args) + + self.patch(action_queue.ActionQueue, "get_webclient", + fake_get_webclient) + self.patch(action_queue.txweb.WebClient, "request", + lambda *args, **kwargs: defer.succeed(None)) + + yield self.action_queue.webcall(self.fake_iri) + self.assertEqual(called_args, [(self.fake_iri,)]) @defer.inlineCallbacks - def test_get_webclient_existing(self): - """The webclient is not created again if it exists.""" - fake_wc = object() - self.patch(self.action_queue, "webclient", fake_wc) - webclient = yield self.action_queue.get_webclient() - self.assertEqual(webclient, fake_wc) + def test_get_webclient(self): + """The webclient is created every time.""" + webclient1 = yield self.action_queue.get_webclient(self.fake_iri) + webclient2 = yield self.action_queue.get_webclient(self.fake_iri) + self.assertNotEqual(webclient1, webclient2) + + @defer.inlineCallbacks + def test_get_webclient_creates_context_with_host(self): + """The ssl context is created with the right host.""" + used_host = [] + + def fake_get_ssl_context(disable_ssl_verify, host): + """The host is used to call get_ssl_context.""" + used_host.append(host) + + self.patch(action_queue, "get_ssl_context", fake_get_ssl_context) + yield self.action_queue.get_webclient(self.fake_iri) + self.assertEqual(used_host, [self.fake_host]) + + @defer.inlineCallbacks + def test_get_webclient_uses_just_created_context(self): + """The freshly created context is used to create the webclient.""" + calls = [] + fake_context = object() + self.patch(action_queue, "get_ssl_context", lambda *args: fake_context) + self.patch(action_queue.txweb.WebClient, "__init__", + lambda *args, **kwargs: calls.append(kwargs)) + yield self.action_queue.get_webclient(self.fake_iri) + self.assertEqual(calls[1]["context_factory"], fake_context) class TestLoggingStorageClient(TwistedTestCase): @@ -1288,6 +1346,7 @@ orig = self.action_queue.clientConnectionLost d = defer.Deferred() + def faked_connectionLost(*args, **kwargs): """Receive connection lost and check.""" orig(*args, **kwargs) @@ -1373,6 +1432,24 @@ "connectSSL is called on the client.") +class ContextRequestedWithHost(FactoryBaseTestCase): + """Test that the context is requested passing the host.""" + + tunnel_runner_class = SavingConnectionTunnelRunner + + @defer.inlineCallbacks + def test_context_request_passes_host(self): + """The context is requested passing the host.""" + fake_host = "fake_host" + + def fake_get_ssl_context(disable_ssl_verify, host): + """The host is used to call get_ssl_context.""" + self.assertEqual(host, fake_host) + + self.patch(action_queue, "get_ssl_context", fake_get_ssl_context) + yield self.action_queue._make_connection((fake_host, 1234)) + + class ConnectedBaseTestCase(FactoryBaseTestCase): """Base test case generating a connected factory.""" @@ -3687,6 +3764,18 @@ cmd._acquire_pathlock() self.assertEqual(t, [('foo', 'bar'), {'logger': None}]) + def test_handle_failure_push_event(self): + """Test AQ_CREATE_SHARE_ERROR is pushed on failure.""" + msg = 'Something went wrong' + failure = Failure(DefaultException(msg)) + cmd = CreateShare(self.request_queue, NODE, 'share_to', + 'share_name', ACCESS_LEVEL_RO, 'marker_id', + os.path.join('foo', 'bar')) + cmd.handle_failure(failure=failure) + events = [('AQ_CREATE_SHARE_ERROR', + {'marker': 'marker_id', 'error': msg})] + self.assertEqual(events, cmd.action_queue.event_queue.events) + class DeleteShareTestCase(ConnectedBaseTestCase): """Test for DeleteShare ActionQueueCommand.""" @@ -4456,6 +4545,15 @@ cmd = GetDelta(self.rq, 'vol', 1) self.assertEqual(cmd.uniqueness, ('GetDelta', 'vol')) + def test_path_locking(self): + """Test that it acquires correctly the path lock.""" + t = [] + self.patch(PathLockingTree, 'acquire', + lambda s, *a, **k: t.extend((a, k))) + cmd = GetDelta(self.rq, 'volume_id', 123) + cmd._acquire_pathlock() + self.assertEqual(t, [('GetDelta', 'volume_id'), {'logger': None}]) + class GetDeltaFromScratchTestCase(ConnectedBaseTestCase): """Test for GetDelta ActionQueueCommand.""" @@ -5858,3 +5956,93 @@ self.assertEqual(called[0], ((FakeCommand, 'arg0'), {'bar': 'baz'})) self.assertEqual(called[1], ((FakeCommand, 'arg1'), {'foo': 'bar'})) self.assertEqual(called[2], ((FakeCommand, 'arg2'), {})) + + def test_execute_pushing_popping(self): + """Exercise the limits when pushing/popping to disk.""" + aq = self.action_queue + aq.memory_pool_limit = 2 + + def _fake_execute(_, cmd): + """Don't really execute, but store and return deferred. + + It also handles the queue. + """ + d = defer.Deferred() + commands.append((cmd, d)) + aq.queue.append(cmd) + + def remove(_): + aq.queue.remove(cmd) + commands.remove((cmd, d)) + + d.addCallback(remove) + return d + + commands = [] + self.patch(aq, '_really_execute', _fake_execute) + aq.disk_queue = FakeOffloadQueue() + aq.queue = [] + aq.commands[FakeCommand.__name__] = FakeCommand + + # send two commands, they should be executed right away + aq.execute(FakeCommand, 1) + aq.execute(FakeCommand, 2) + self.assertEqual(commands[0][0], 1) + self.assertEqual(commands[1][0], 2) + + # send a third and fourth commands, they should be offloaded + aq.execute(FakeCommand, 3) + aq.execute(FakeCommand, 4) + self.assertEqual(len(commands), 2) + self.assertEqual(len(aq.disk_queue), 2) + self.assertEqual(aq.disk_queue[0], ('FakeCommand', (3,), {})) + self.assertEqual(aq.disk_queue[1], ('FakeCommand', (4,), {})) + + # finish command 1, it should pop and execute command 3 + commands[0][1].callback(True) + self.assertEqual(len(commands), 2) + self.assertEqual(commands[0][0], 2) + self.assertEqual(commands[1][0], 3) + self.assertEqual(len(aq.disk_queue), 1) + self.assertEqual(aq.disk_queue[0], ('FakeCommand', (4,), {})) + + # other command should go offload + aq.execute(FakeCommand, 5) + self.assertEqual(len(commands), 2) + self.assertEqual(len(aq.disk_queue), 2) + self.assertEqual(aq.disk_queue[0], ('FakeCommand', (4,), {})) + self.assertEqual(aq.disk_queue[1], ('FakeCommand', (5,), {})) + + # finish commands 2 and 3... 4 and 5 should go in + commands[0][1].callback(True) + commands[0][1].callback(True) + self.assertEqual(len(commands), 2) + self.assertEqual(commands[0][0], 4) + self.assertEqual(commands[1][0], 5) + self.assertEqual(len(aq.disk_queue), 0) + + # even in the edge, another command should be offloaded + aq.execute(FakeCommand, 6) + self.assertEqual(len(commands), 2) + self.assertEqual(len(aq.disk_queue), 1) + self.assertEqual(aq.disk_queue[0], ('FakeCommand', (6,), {})) + + # finish 4 and 5, we should only have 6 left + commands[0][1].callback(True) + commands[0][1].callback(True) + self.assertEqual(len(commands), 1) + self.assertEqual(commands[0][0], 6) + self.assertEqual(len(aq.disk_queue), 0) + + # one below the limit, next op should be executed right away + aq.execute(FakeCommand, 7) + self.assertEqual(len(commands), 2) + self.assertEqual(commands[0][0], 6) + self.assertEqual(commands[1][0], 7) + self.assertEqual(len(aq.disk_queue), 0) + + # finish 6 and 7, all clean + commands[0][1].callback(True) + commands[0][1].callback(True) + self.assertEqual(len(commands), 0) + self.assertEqual(len(aq.disk_queue), 0) Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_action_queue.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_action_queue.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_config.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_config.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_eq_inotify.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_eq_inotify.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_eventqueue.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_eventqueue.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_eventsnanny.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_eventsnanny.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_fileshelf.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_fileshelf.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_fsm.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_fsm.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_hashqueue.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_hashqueue.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_interaction_interfaces.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_interaction_interfaces.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_localrescan.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_localrescan.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_logger.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_logger.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_main.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_main.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_mutefilter.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_mutefilter.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_offloadqueue.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_offloadqueue.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_pathlockingtree.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_pathlockingtree.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_states.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_states.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_status_listener.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_status_listener.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_sync.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_sync.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_tritcask.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_tritcask.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_tunnel_runner.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_tunnel_runner.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_u1fsfsm.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_u1fsfsm.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_vm_helper.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_vm_helper.pyc differ Binary files /tmp/u1HXUT3ufC/ubuntuone-client-3.0.0/tests/syncdaemon/test_vm.pyc and /tmp/Dkkd4LG0lc/ubuntuone-client-3.0.2/tests/syncdaemon/test_vm.pyc differ diff -Nru ubuntuone-client-3.0.0/ubuntuone/platform/credentials/linux.py ubuntuone-client-3.0.2/ubuntuone/platform/credentials/linux.py --- ubuntuone-client-3.0.0/ubuntuone/platform/credentials/linux.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/ubuntuone/platform/credentials/linux.py 2012-06-14 20:17:10.000000000 +0000 @@ -30,6 +30,7 @@ # files in the program, then also delete it here. """Ubuntu One credentials management dbus service.""" +import dbus import dbus.service import ubuntu_sso @@ -181,7 +182,8 @@ def find_credentials(self, reply_handler=NO_OP, error_handler=NO_OP): """Ask the Ubuntu One credentials.""" self.ref_count += 1 - self.sso_proxy.find_credentials(APP_NAME, {}, + self.sso_proxy.find_credentials(APP_NAME, + dbus.Dictionary({}, signature='ss'), reply_handler=reply_handler, error_handler=error_handler) @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, @@ -205,7 +207,9 @@ self.ref_count -= 1 self.ref_count += 1 - self.sso_proxy.find_credentials_sync(APP_NAME, {}, + self.sso_proxy.find_credentials_sync( + APP_NAME, + dbus.Dictionary({}, signature='ss'), reply_handler=decrease_counter_success, error_handler=decrease_counter_error) @@ -214,7 +218,8 @@ def clear_credentials(self, reply_handler=NO_OP, error_handler=NO_OP): """Clear the Ubuntu One credentials.""" self.ref_count += 1 - self.sso_proxy.clear_credentials(APP_NAME, {}, + self.sso_proxy.clear_credentials(APP_NAME, + dbus.Dictionary({}, signature='ss'), reply_handler=reply_handler, error_handler=error_handler) @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, diff -Nru ubuntuone-client-3.0.0/ubuntuone/platform/linux/filesystem_notifications.py ubuntuone-client-3.0.2/ubuntuone/platform/linux/filesystem_notifications.py --- ubuntuone-client-3.0.0/ubuntuone/platform/linux/filesystem_notifications.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/ubuntuone/platform/linux/filesystem_notifications.py 2012-06-14 20:17:10.000000000 +0000 @@ -214,6 +214,16 @@ if not (event.mask & pyinotify.IN_ISDIR): self.general_processor.push_event(event) + @validate_filename + def process_IN_CLOSE_WRITE(self, event): + """Filter IN_CLOSE_WRITE to make it happen only in files. + + eCryptFS sends IN_CLOSE_WRITE event for lower directories. + + """ + if not (event.mask & pyinotify.IN_ISDIR): + self.general_processor.push_event(event) + def process_IN_MOVE_SELF(self, event): """Don't do anything here. diff -Nru ubuntuone-client-3.0.0/ubuntuone/platform/tools/windows.py ubuntuone-client-3.0.2/ubuntuone/platform/tools/windows.py --- ubuntuone-client-3.0.0/ubuntuone/platform/tools/windows.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/ubuntuone/platform/tools/windows.py 2012-06-14 20:17:10.000000000 +0000 @@ -126,10 +126,12 @@ def __init__(self, bus=None): self.client = UbuntuOneClient() - self.connected = self.client.connect() + self.connected = None def _call_after_connection(self, method): """Make sure Perspective Broker is connected before calling.""" + if not self.client.is_connected(): + self.connected = self.client.connect() @defer.inlineCallbacks def call_after_connection_inner(*args, **kwargs): diff -Nru ubuntuone-client-3.0.0/ubuntuone/platform/windows/ipc_client.py ubuntuone-client-3.0.2/ubuntuone/platform/windows/ipc_client.py --- ubuntuone-client-3.0.0/ubuntuone/platform/windows/ipc_client.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/ubuntuone/platform/windows/ipc_client.py 2012-06-14 20:17:10.000000000 +0000 @@ -759,6 +759,10 @@ 'Could not connect to the syncdaemon ipc.', e) # pylint: disable=W0702 + def is_connected(self): + """Return if the client is connected.""" + return (self.client is not None) + @defer.inlineCallbacks def register_to_signals(self): """Register the different clients to the signals.""" diff -Nru ubuntuone-client-3.0.0/ubuntuone/platform/windows/os_helper.py ubuntuone-client-3.0.2/ubuntuone/platform/windows/os_helper.py --- ubuntuone-client-3.0.0/ubuntuone/platform/windows/os_helper.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/ubuntuone/platform/windows/os_helper.py 2012-06-14 20:17:10.000000000 +0000 @@ -35,7 +35,6 @@ import stat import sys -from platform import version from contextlib import contextmanager from functools import wraps @@ -885,13 +884,11 @@ def is_root(): """Return if the user is running as root.""" - # On Windows XP (v5.1), always return False. Nearly all users run with - # Administrator access, so this would restrict too many users. - # On Vista (v6.0) and 7 (v6.1), return the real Administrator value. - # The MSDN docs say this may go away in a later version, but look at what - # the alternative is: http://bit.ly/rXbIwc - is_xp = version()[0] == "5" - return False if is_xp else shell.IsUserAnAdmin() + # Always return False. Trying to be smart about OS versions and + # only calling Windows APIs under certain conditions has still + # proven not to work in some cases. Overall it should not matter + # if we know whether we are Administrator or not on Windows. + return False @windowspath() diff -Nru ubuntuone-client-3.0.0/ubuntuone/proxy/tunnel_client.py ubuntuone-client-3.0.2/ubuntuone/proxy/tunnel_client.py --- ubuntuone-client-3.0.0/ubuntuone/proxy/tunnel_client.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/ubuntuone/proxy/tunnel_client.py 2012-06-14 20:17:10.000000000 +0000 @@ -143,7 +143,7 @@ class TunnelProcessProtocol(protocol.ProcessProtocol): """The dialog thru stdout with the tunnel server.""" - timeout = 5 + timeout = 30 def __init__(self, client_d): """Initialize this protocol.""" diff -Nru ubuntuone-client-3.0.0/ubuntuone/syncdaemon/action_queue.py ubuntuone-client-3.0.2/ubuntuone/syncdaemon/action_queue.py --- ubuntuone-client-3.0.0/ubuntuone/syncdaemon/action_queue.py 2012-04-11 15:09:28.000000000 +0000 +++ ubuntuone-client-3.0.2/ubuntuone/syncdaemon/action_queue.py 2012-06-14 20:17:10.000000000 +0000 @@ -43,7 +43,7 @@ from collections import deque, defaultdict from functools import partial from urllib import urlencode -from urlparse import urljoin +from urlparse import urljoin, urlparse import OpenSSL.SSL @@ -697,7 +697,6 @@ self.token = None self.consumer = None self.credentials = None - self.webclient = None self.client = None # an instance of self.protocol @@ -836,26 +835,28 @@ @defer.inlineCallbacks def webcall(self, iri, **kwargs): """Perform a web call to the api servers.""" - webclient = yield self.get_webclient() + webclient = yield self.get_webclient(iri) response = yield webclient.request(iri, oauth_credentials=self.credentials, **kwargs) defer.returnValue(response) @defer.inlineCallbacks - def get_webclient(self): + def get_webclient(self, iri): """Get the webclient, creating it if needed.""" - if self.webclient is None: - client = yield self.tunnel_runner.get_client() - self.webclient = txweb.WebClient(connector=client, - appname="Ubuntu One", - oauth_sign_plain=True) - defer.returnValue(self.webclient) + uri = txweb.WebClient().iri_to_uri(iri) + host = urlparse(uri).netloc.split(":")[0] + ssl_context = get_ssl_context(self.disable_ssl_verify, host) + connector = yield self.tunnel_runner.get_client() + webclient = txweb.WebClient(connector=connector, appname="Ubuntu One", + oauth_sign_plain=True, + context_factory=ssl_context) + defer.returnValue(webclient) @defer.inlineCallbacks def _make_connection(self, result): """Do the real connect call.""" host, port = result - ssl_context = get_ssl_context(self.disable_ssl_verify) + ssl_context = get_ssl_context(self.disable_ssl_verify, host) client = yield self.tunnel_runner.get_client() if self.use_ssl: self.connector = client.connectSSL(host, port, factory=self, @@ -1095,8 +1096,9 @@ @defer.inlineCallbacks def execute(self, command_class, *args, **kwargs): """Execute a command only if there's room in memory to handle it.""" - if len(self.queue) > self.memory_pool_limit: - # not enough room in memory, store it in the offloaded queue + if len(self.queue) >= self.memory_pool_limit: + # already in the limit, can't go further as we don't have + # more room in memory, store it in the offloaded queue logger.debug('offload push: %s %s %s', command_class.__name__, args, kwargs) self.disk_queue.push((command_class.__name__, args, kwargs)) return @@ -1851,7 +1853,7 @@ """It didn't work! Push the event.""" self.action_queue.event_queue.push('AQ_CREATE_SHARE_ERROR', marker=self.marker, - error=failure.value[1]) + error=failure.getErrorMessage()) def _acquire_pathlock(self): """Acquire pathlock.""" @@ -2069,6 +2071,12 @@ self.log = mklog(logger, 'GetDelta', self.volume_id, None, generation=self.generation) + def _acquire_pathlock(self): + """Acquire pathlock.""" + pathlock = self.action_queue.pathlock + return pathlock.acquire('GetDelta', str(self.volume_id), + logger=self.log) + class GetDeltaFromScratch(ActionQueueCommand): """Get a delta from scratch."""