Merge lp:~dobey/ubuntuone-client/update-4-0 into lp:ubuntuone-client/stable-4-0

Proposed by dobey on 2012-08-28
Status: Merged
Merged at revision: 1258
Proposed branch: lp:~dobey/ubuntuone-client/update-4-0
Merge into: lp:ubuntuone-client/stable-4-0
Diff against target: 320 lines (+134/-8)
8 files modified
bin/ubuntuone-syncdaemon (+1/-0)
run-mac-tests (+3/-1)
tests/platform/tools/test_tools.py (+64/-0)
tests/syncdaemon/test_hashqueue.py (+2/-0)
ubuntuone/platform/filesystem_notifications/monitor/__init__.py (+14/-3)
ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_client.py (+1/-1)
ubuntuone/platform/ipc/ipc_client.py (+12/-0)
ubuntuone/platform/tools/perspective_broker.py (+37/-3)
To merge this branch: bzr merge lp:~dobey/ubuntuone-client/update-4-0
Reviewer Review Type Date Requested Status
Eric Casteleijn (community) 2012-08-28 Approve on 2012-08-28
Review via email: mp+121684@code.launchpad.net

Commit Message

[Rodney Dawes]

    - Skip the test_being_hashed for now as it causes intermittent failures.

[Manuel de la Peña]

    - Fix stale broker problems by reconnecting to the server and requesting new valid instances for the reference objects in the client side (LP: #1040915).
    - Use the correct logger.
    - Used the new API (LP: #1040170).
    - Create events now have in_modify thx to the new API (LP: #1034127).

[Mike McCracken]

    - Fix typo in log format specifier.
    - Log to syncdaemon log which monitor implementation is used. (LP: #1042336)
    - Remove broken buildout env vars, and add lint to mac test script. (LP: #1037432)

[Alejandro J. Cura]

    - Log exceptions when running async_main (LP: #1041163).

To post a comment you must log in.
Eric Casteleijn (thisfred) :
review: Approve
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (255.2 KiB)

The attempt to merge lp:~dobey/ubuntuone-client/update-4-0 into lp:ubuntuone-client/stable-4-0 failed. Below is the output from the failed tests.

/usr/bin/gnome-autogen.sh
checking for autoconf >= 2.53...
  testing autoconf2.50... not found.
  testing autoconf... found 2.69
checking for automake >= 1.10...
  testing automake-1.11... found 1.11.5
checking for libtool >= 1.5...
  testing libtoolize... found 2.4.2
checking for intltool >= 0.30...
  testing intltoolize... found 0.50.2
checking for pkg-config >= 0.14.0...
  testing pkg-config... found 0.26
checking for gtk-doc >= 1.0...
  testing gtkdocize... found 1.18
Checking for required M4 macros...
Checking for forbidden M4 macros...
Processing ./configure.ac
Running libtoolize...
libtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
Running intltoolize...
Running gtkdocize...
Running aclocal-1.11...
Running autoconf...
Running autoheader...
Running automake-1.11...
Running ./configure --enable-gtk-doc --enable-debug ...
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking how to create a ustar tar archive... gnutar
checking whether make supports nested variables... yes
checking for style of include used by make... GNU
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking dependency style of gcc... gcc3
checking for library containing strerror... none required
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking dependency style of gcc... (cached) gcc3
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking how to print strings... printf
checking for a sed that does not truncate output... /bin/sed
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for fgrep... /bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 1572864
checking whether the shell understands some XSI constructs......

1258. By dobey on 2012-08-29

[Rodney Dawes]

    - Skip the test_being_hashed for now as it causes intermittent failures.

[Manuel de la Peña]

    - Fix stale broker problems by reconnecting to the server and requesting new valid instances for the reference objects in the client side (LP: #1040915).
    - Use the correct logger.
    - Used the new API (LP: #1040170).
    - Create events now have in_modify thx to the new API (LP: #1034127).

[Mike McCracken]

    - Fix typo in log format specifier.
    - Log to syncdaemon log which monitor implementation is used. (LP: #1042336)
    - Remove broken buildout env vars, and add lint to mac test script. (LP: #1037432)

[Alejandro J. Cura]

    - Log exceptions when running async_main (LP: #1041163).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/ubuntuone-syncdaemon'
2--- bin/ubuntuone-syncdaemon 2012-07-26 22:00:58 +0000
3+++ bin/ubuntuone-syncdaemon 2012-08-28 19:24:19 +0000
4@@ -104,6 +104,7 @@
5 args=args, usage=usage)
6 d = async_main(parser, options, argv)
7 d.addErrback(check_death)
8+ d.addErrback(logger.root_logger.exception)
9
10 # check if we should start a twisted manhole
11 if options.debug_manhole:
12
13=== modified file 'run-mac-tests'
14--- run-mac-tests 2012-08-01 14:25:58 +0000
15+++ run-mac-tests 2012-08-28 19:24:19 +0000
16@@ -42,8 +42,10 @@
17 cp windows/clientdefs.py ubuntuone/clientdefs.py
18 cp windows/logging.conf data/logging.conf
19 # execute the tests with a number of ignored linux only modules
20-python $u1trial --reactor=twisted -i "test_linux.py,test_windows.py" -p tests/platform/linux "$MODULE"
21+u1trial --reactor=twisted -i "test_linux.py,test_windows.py" -p tests/platform/linux "$MODULE"
22 rm -rf _trial_temp
23 rm -rf build
24
25 python tests/platform/check_reactor_import.py
26+
27+USE_PYFLAKES="true" u1lint
28
29=== modified file 'tests/platform/tools/test_tools.py'
30--- tests/platform/tools/test_tools.py 2012-05-24 15:09:34 +0000
31+++ tests/platform/tools/test_tools.py 2012-08-28 19:24:19 +0000
32@@ -32,6 +32,7 @@
33 import operator
34
35 from twisted.internet import defer
36+from twisted.spread import pb
37 from twisted.trial.unittest import TestCase
38
39 from ubuntuone.platform.tools import perspective_broker
40@@ -125,3 +126,66 @@
41 attr = getattr(self.sdtool, attr_name)
42 func_name = getattr(attr, "__name__", None)
43 self.assertNotEqual(func_name, "call_after_connection_inner")
44+
45+
46+class FakeRemoteObject(object):
47+ """Fake a remote object."""
48+
49+ def __init__(self):
50+ """Create a new instance."""
51+ self.number_calls = 0
52+ self.called = []
53+
54+ def method_call(self, *args, **kwargs):
55+ """Fake a remote method call."""
56+ if self.number_calls == 0:
57+ self.number_calls += 1
58+ raise pb.DeadReferenceError()
59+ else:
60+ self.called.append((args, kwargs))
61+ return defer.succeed(self.number_calls)
62+
63+
64+class PerspectiveBrokerReconnect(TestCase):
65+ """Test when the ipc is reconnected."""
66+
67+ @defer.inlineCallbacks
68+ def setUp(self):
69+ """Set the tests."""
70+ yield super(PerspectiveBrokerReconnect, self).setUp()
71+ self.sdtool = perspective_broker.SyncDaemonToolProxy()
72+ self.sdtool.client.fake_remote = FakeRemoteObject()
73+ self.connected_signals = []
74+ self.reconnected = False
75+
76+ def connect_signal(my_self, *args, **kwargs):
77+ """Fake connect_signal call."""
78+ self.connected_signals.append(('connect_signal', args, kwargs))
79+
80+ self.patch(perspective_broker.SyncDaemonToolProxy, 'connect_signal',
81+ connect_signal)
82+
83+ def fake_reconnect(_):
84+ """Fake the reconnection of the client."""
85+ self.reconnected = True
86+
87+ self.patch(perspective_broker.UbuntuOneClient, 'reconnect',
88+ fake_reconnect)
89+ self.patch(perspective_broker.UbuntuOneClient, 'connect',
90+ lambda _: defer.succeed(True))
91+
92+ @defer.inlineCallbacks
93+ def test_reconnect_no_signals(self):
94+ """Test reconnection with no signals."""
95+ yield self.sdtool.call_method('fake_remote', 'method_call')
96+ self.assertTrue(self.reconnected)
97+ self.assertEqual(0, len(self.connected_signals))
98+
99+ @defer.inlineCallbacks
100+ def test_reconnect_signals(self):
101+ """Test reconnection with signals."""
102+ self.sdtool.connected_signals = dict(create_signal=lambda:None,
103+ delete_signal=lambda:None)
104+ yield self.sdtool.call_method('fake_remote', 'method_call')
105+ self.assertTrue(self.reconnected)
106+ self.assertEqual(2, len(self.connected_signals))
107
108=== modified file 'tests/syncdaemon/test_hashqueue.py'
109--- tests/syncdaemon/test_hashqueue.py 2012-04-09 20:07:05 +0000
110+++ tests/syncdaemon/test_hashqueue.py 2012-08-28 19:24:19 +0000
111@@ -42,6 +42,7 @@
112 from twisted.trial.unittest import TestCase as TwistedTestCase
113 from twisted.internet import defer, reactor
114 from ubuntuone.devtools.handlers import MementoHandler
115+from ubuntuone.devtools.testcases import skipTest
116
117 from contrib.testing.testcase import BaseTwistedTestCase
118 from ubuntuone.platform import open_file, stat_path
119@@ -583,6 +584,7 @@
120 self.assertEqual(kwargs['mdid'], "foo")
121 self.assertTrue(call_later_called)
122
123+ @skipTest('Causing intermittent failures. LP: #935568')
124 def test_being_hashed(self):
125 """Tell if something is being hashed."""
126 tfile1 = os.path.join(self.test_dir, "tfile1")
127
128=== modified file 'ubuntuone/platform/filesystem_notifications/monitor/__init__.py'
129--- ubuntuone/platform/filesystem_notifications/monitor/__init__.py 2012-08-01 14:25:58 +0000
130+++ ubuntuone/platform/filesystem_notifications/monitor/__init__.py 2012-08-28 19:24:19 +0000
131@@ -28,11 +28,14 @@
132 # files in the program, then also delete it here.
133 """Filesystem monitors per platform."""
134
135+import logging
136 import sys
137
138 from twisted.internet import defer
139
140 DEFAULT_MONITOR = 'default'
141+logger = logging.getLogger('ubuntuone.SyncDaemon.platform.' +
142+ 'filesystem_notifications.monitor')
143
144
145 class NoAvailableMonitorError(Exception):
146@@ -70,6 +73,7 @@
147 DEFAULT_MONITOR: linux.FilesystemMonitor,
148 }
149
150+
151 # mantain old API
152 FilesystemMonitor = FILEMONITOR_IDS[DEFAULT_MONITOR]
153
154@@ -77,21 +81,28 @@
155 @defer.inlineCallbacks
156 def get_filemonitor_class(monitor_id=None):
157 """Return the class to be used."""
158+ logger.debug('File monitor ids for platform "%s" are "%s"', sys.platform,
159+ FILEMONITOR_IDS)
160+
161 if monitor_id is None:
162- # use default
163+ logger.debug('monitor_id is None, using default.')
164 monitor_id = 'default'
165
166 if monitor_id not in FILEMONITOR_IDS:
167- raise NoAvailableMonitorError(
168- 'No available monitor with id "%s"could be found.' % monitor_id)
169+ msg = 'No available monitor with id %r could be found.'
170+ raise NoAvailableMonitorError(msg % monitor_id)
171
172 # retrieve the correct class and assert it can be used
173 cls = FILEMONITOR_IDS[monitor_id]
174+ logger.debug('Checking availability of monitor class %s', cls)
175 is_available = yield cls.is_available_monitor()
176
177 if is_available:
178+ logger.debug('Monitor is available, returning monitor with id "%s"',
179+ monitor_id)
180 defer.returnValue(cls)
181 elif not is_available and monitor_id != DEFAULT_MONITOR:
182+ logger.debug('Monitor is NOT available, returning default monitor.')
183 cls = yield get_filemonitor_class(DEFAULT_MONITOR)
184 defer.returnValue(cls)
185 else:
186
187=== modified file 'ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_client.py'
188--- ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_client.py 2012-07-13 15:08:15 +0000
189+++ ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_client.py 2012-08-28 19:24:19 +0000
190@@ -124,7 +124,7 @@
191 def __init__(self, log):
192 """Init the manager to keep track of the different watches."""
193 self.log = log
194- self.observer = fsevents.Observer()
195+ self.observer = fsevents.Observer(latency=0, process_asap=True)
196 self.observer.start()
197
198 def stop_watch(self, watch):
199
200=== modified file 'ubuntuone/platform/ipc/ipc_client.py'
201--- ubuntuone/platform/ipc/ipc_client.py 2012-08-16 12:00:12 +0000
202+++ ubuntuone/platform/ipc/ipc_client.py 2012-08-28 19:24:19 +0000
203@@ -778,6 +778,18 @@
204 'Could not connect to the syncdaemon ipc.', e)
205 # pylint: disable=W0702
206
207+ @defer.inlineCallbacks
208+ def reconnect(self):
209+ """Reconnect and get the new remote objects."""
210+ try:
211+ root = yield self.factory.getRootObject()
212+ yield self._request_remote_objects(root)
213+ yield self.register_to_signals()
214+ defer.returnValue(self)
215+ except Exception, e:
216+ raise SyncDaemonClientConnectionError(
217+ 'Could not reconnect to the syncdaemon ipc.', e)
218+
219 def is_connected(self):
220 """Return if the client is connected."""
221 return (self.client is not None)
222
223=== modified file 'ubuntuone/platform/tools/perspective_broker.py'
224--- ubuntuone/platform/tools/perspective_broker.py 2012-07-13 16:06:27 +0000
225+++ ubuntuone/platform/tools/perspective_broker.py 2012-08-28 19:24:19 +0000
226@@ -28,9 +28,11 @@
227 # files in the program, then also delete it here.
228 """SyncDaemon Tools."""
229
230+import logging
231 import subprocess
232
233 from twisted.internet import defer
234+from twisted.spread.pb import DeadReferenceError
235
236 from ubuntuone.platform.ipc.perspective_broker import is_already_running
237 from ubuntuone.platform.ipc.ipc_client import UbuntuOneClient
238@@ -99,6 +101,7 @@
239 _DONT_VERIFY_CONNECTED = [
240 "wait_connected",
241 "client", "last_event", "delayed_call", "log", "connected",
242+ "connected_signals"
243 ]
244
245 def _should_wrap(self, attr_name):
246@@ -115,8 +118,11 @@
247 return attr
248
249 def __init__(self, bus=None):
250+ self.log = logging.getLogger('ubuntuone.platform.tools.' +
251+ 'perspective_broker')
252 self.client = UbuntuOneClient()
253 self.connected = None
254+ self.connected_signals = {}
255
256 def _call_after_connection(self, method):
257 """Make sure Perspective Broker is connected before calling."""
258@@ -127,17 +133,41 @@
259 def call_after_connection_inner(*args, **kwargs):
260 """Call the given method after the connection to pb is made."""
261 yield self.connected
262- retval = yield method(*args, **kwargs)
263+ try:
264+ retval = yield method(*args, **kwargs)
265+ except DeadReferenceError:
266+ self.log.debug('Got stale broker, atempting reconnect.')
267+ # might be the case where we have a stale broker
268+ yield self._reconnect_client()
269+ retval = yield method(*args, **kwargs)
270 defer.returnValue(retval)
271
272 return call_after_connection_inner
273
274+ @defer.inlineCallbacks
275+ def _reconnect_client(self):
276+ """Reconnect the client."""
277+ self.connected = False
278+ yield self.client.reconnect()
279+ # do connect all the signals again
280+ for signal_name, handler in self.connected_signals.items():
281+ self.connect_signal(signal_name, handler)
282+
283+ @defer.inlineCallbacks
284 def call_method(self, client_kind, method_name, *args, **kwargs):
285 """Call the 'method_name' passing 'args' and 'kwargs'."""
286 client = getattr(self.client, client_kind)
287 method = getattr(client, method_name)
288- result = method(*args, **kwargs)
289- return result
290+ try:
291+ result = yield method(*args, **kwargs)
292+ except DeadReferenceError:
293+ self.log.debug('Got stale broker, atempting reconnect.')
294+ # may happen in the case we reconnected and the server side objects
295+ # for gc
296+ yield self._reconnect_client()
297+ result = yield self.call_method(client_kind, method_name,
298+ *args, **kwargs)
299+ defer.returnValue(result)
300
301 def shutdown(self):
302 """Close connections."""
303@@ -148,6 +178,8 @@
304 client_kind, callback = self._SIGNAL_MAPPING[signal_name]
305 client = getattr(self.client, client_kind)
306 setattr(client, callback, handler)
307+ # do remember the connected signal in case we need to reconnect
308+ self.connected_signals[signal_name] = handler
309 return handler
310
311 def disconnect_signal(self, signal_name, handler_or_match):
312@@ -155,6 +187,8 @@
313 client_kind, callback = self._SIGNAL_MAPPING[signal_name]
314 client = getattr(self.client, client_kind)
315 setattr(client, callback, None)
316+ # forget that the connection was made in case we need to reconnect
317+ del self.connected_signals[signal_name]
318 return handler_or_match
319
320 def wait_connected(self):

Subscribers

People subscribed via source and target branches

to all changes: