Merge lp:~facundo/magicicada-client/full-closed-venv into lp:magicicada-client
- full-closed-venv
- Merge into trunk
Proposed by
Facundo Batista
Status: | Merged |
---|---|
Approved by: | Natalia Bidart |
Approved revision: | 1447 |
Merged at revision: | 1447 |
Proposed branch: | lp:~facundo/magicicada-client/full-closed-venv |
Merge into: | lp:magicicada-client |
Diff against target: |
4651 lines (+2923/-353) 62 files modified
Makefile (+1/-1) contrib/devtools/__init__.py (+1/-0) contrib/devtools/compat.py (+49/-0) contrib/devtools/errors.py (+35/-0) contrib/devtools/handlers.py (+97/-0) contrib/devtools/reactors/__init__.py (+1/-0) contrib/devtools/reactors/gi.py (+53/-0) contrib/devtools/runners/__init__.py (+305/-0) contrib/devtools/runners/txrunner.py (+133/-0) contrib/devtools/services/__init__.py (+66/-0) contrib/devtools/services/dbus.py (+119/-0) contrib/devtools/testcases/__init__.py (+187/-0) contrib/devtools/testcases/dbus.py (+138/-0) contrib/devtools/testcases/txsocketserver.py (+358/-0) contrib/devtools/testing/__init__.py (+1/-0) contrib/devtools/testing/txcheck.py (+381/-0) contrib/devtools/testing/txwebserver.py (+125/-0) contrib/devtools/utils.py (+181/-0) contrib/dirspec/__init__.py (+16/-0) contrib/dirspec/basedir.py (+159/-0) contrib/dirspec/utils.py (+188/-0) contrib/u1trial (+41/-0) dependencies-devel.txt (+0/-3) dependencies.txt (+5/-8) magicicadaclient/platform/tests/filesystem_notifications/__init__.py (+3/-2) magicicadaclient/platform/tests/filesystem_notifications/common.py (+12/-13) magicicadaclient/platform/tests/filesystem_notifications/test_darwin.py (+10/-9) magicicadaclient/platform/tests/filesystem_notifications/test_filesystem_notifications.py (+2/-1) magicicadaclient/platform/tests/filesystem_notifications/test_fsevents_daemon.py (+10/-15) magicicadaclient/platform/tests/ipc/test_linux.py (+2/-4) magicicadaclient/platform/tests/ipc/test_perspective_broker.py (+3/-8) magicicadaclient/platform/tests/os_helper/test_darwin.py (+3/-7) magicicadaclient/platform/tests/os_helper/test_linux.py (+3/-6) magicicadaclient/platform/tests/session/test_common.py (+2/-1) magicicadaclient/platform/tests/session/test_linux.py (+7/-13) magicicadaclient/platform/tests/test_tools.py (+4/-6) magicicadaclient/syncdaemon/tests/test_action_queue.py (+14/-14) magicicadaclient/syncdaemon/tests/test_eq_inotify.py (+11/-15) magicicadaclient/syncdaemon/tests/test_eventqueue.py (+2/-6) magicicadaclient/syncdaemon/tests/test_fileshelf.py (+26/-31) magicicadaclient/syncdaemon/tests/test_fsm.py (+36/-33) magicicadaclient/syncdaemon/tests/test_hashqueue.py (+16/-16) magicicadaclient/syncdaemon/tests/test_interaction_interfaces.py (+11/-15) magicicadaclient/syncdaemon/tests/test_localrescan.py (+15/-15) magicicadaclient/syncdaemon/tests/test_logger.py (+5/-7) magicicadaclient/syncdaemon/tests/test_main.py (+5/-5) magicicadaclient/syncdaemon/tests/test_offloadqueue.py (+3/-2) magicicadaclient/syncdaemon/tests/test_pathlockingtree.py (+2/-5) magicicadaclient/syncdaemon/tests/test_sync.py (+13/-9) magicicadaclient/syncdaemon/tests/test_tritcask.py (+11/-13) magicicadaclient/syncdaemon/tests/test_vm.py (+11/-9) magicicadaclient/testing/testcase.py (+1/-1) magicicadaclient/utils/__init__.py (+3/-4) magicicadaclient/utils/tests/test_common.py (+4/-4) magicicadaclient/utils/tests/test_ipc.py (+5/-5) magicicadaclient/utils/tests/test_tcpactivation.py (+2/-5) magicicadaclient/utils/tests/test_translation.py (+1/-1) magicicadaclient/utils/tests/test_txsecrets.py (+2/-2) requirements-devel.txt (+2/-0) requirements.txt (+6/-1) run-tests (+1/-1) setup.py (+14/-37) |
To merge this branch: | bzr merge lp:~facundo/magicicada-client/full-closed-venv |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Natalia Bidart | Approve | ||
Review via email:
|
Commit message
Went full venv.
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Makefile' |
2 | --- Makefile 2018-04-14 23:34:20 +0000 |
3 | +++ Makefile 2018-06-03 23:09:20 +0000 |
4 | @@ -43,7 +43,7 @@ |
5 | cat dependencies-devel.txt | xargs apt-get install -y --no-install-recommends |
6 | |
7 | venv: |
8 | - virtualenv --system-site-packages $(ENV) |
9 | + virtualenv $(ENV) |
10 | $(ENV)/bin/pip install -r requirements.txt -r requirements-devel.txt |
11 | |
12 | lint: |
13 | |
14 | === added directory 'contrib/devtools' |
15 | === added file 'contrib/devtools/__init__.py' |
16 | --- contrib/devtools/__init__.py 1970-01-01 00:00:00 +0000 |
17 | +++ contrib/devtools/__init__.py 2018-06-03 23:09:20 +0000 |
18 | @@ -0,0 +1,1 @@ |
19 | +"""Testing utilities for Ubuntu One client code.""" |
20 | |
21 | === added file 'contrib/devtools/compat.py' |
22 | --- contrib/devtools/compat.py 1970-01-01 00:00:00 +0000 |
23 | +++ contrib/devtools/compat.py 2018-06-03 23:09:20 +0000 |
24 | @@ -0,0 +1,49 @@ |
25 | +# -*- coding: utf-8 -*- |
26 | +# |
27 | +# Copyright 2012 Canonical Ltd. |
28 | +# |
29 | +# This program is free software: you can redistribute it and/or modify it |
30 | +# under the terms of the GNU General Public License version 3, as published |
31 | +# by the Free Software Foundation. |
32 | +# |
33 | +# This program is distributed in the hope that it will be useful, but |
34 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
35 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
36 | +# PURPOSE. See the GNU General Public License for more details. |
37 | +# |
38 | +# You should have received a copy of the GNU General Public License along |
39 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
40 | +# |
41 | +# In addition, as a special exception, the copyright holders give |
42 | +# permission to link the code of portions of this program with the |
43 | +# OpenSSL library under certain conditions as described in each |
44 | +# individual source file, and distribute linked combinations |
45 | +# including the two. |
46 | +# You must obey the GNU General Public License in all respects |
47 | +# for all of the code used other than OpenSSL. If you modify |
48 | +# file(s) with this exception, you may extend this exception to your |
49 | +# version of the file(s), but you are not obligated to do so. If you |
50 | +# do not wish to do so, delete this exception statement from your |
51 | +# version. If you delete this exception statement from all source |
52 | +# files in the program, then also delete it here. |
53 | +"""Python 2 and 3 compatibility.""" |
54 | + |
55 | +from __future__ import unicode_literals |
56 | + |
57 | +# The following approach was outlined in Lennart Regebro's |
58 | +# "Porting to Python 3" book. |
59 | +# http://python3porting.com/noconv.html#more-bytes-strings-and-unicode |
60 | + |
61 | +import sys |
62 | + |
63 | +# Disable redefined builtin, invalid name warning |
64 | +# pylint: disable=W0622,C0103 |
65 | + |
66 | +if sys.version_info < (3,): |
67 | + text_type = unicode |
68 | + binary_type = str |
69 | + basestring = basestring |
70 | +else: |
71 | + text_type = str |
72 | + binary_type = bytes |
73 | + basestring = str |
74 | |
75 | === added file 'contrib/devtools/errors.py' |
76 | --- contrib/devtools/errors.py 1970-01-01 00:00:00 +0000 |
77 | +++ contrib/devtools/errors.py 2018-06-03 23:09:20 +0000 |
78 | @@ -0,0 +1,35 @@ |
79 | +# Copyright 2012 Canonical Ltd. |
80 | +# |
81 | +# This program is free software: you can redistribute it and/or modify it |
82 | +# under the terms of the GNU General Public License version 3, as published |
83 | +# by the Free Software Foundation. |
84 | +# |
85 | +# This program is distributed in the hope that it will be useful, but |
86 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
87 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
88 | +# PURPOSE. See the GNU General Public License for more details. |
89 | +# |
90 | +# You should have received a copy of the GNU General Public License along |
91 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
92 | +# |
93 | +# In addition, as a special exception, the copyright holders give |
94 | +# permission to link the code of portions of this program with the |
95 | +# OpenSSL library under certain conditions as described in each |
96 | +# individual source file, and distribute linked combinations |
97 | +# including the two. |
98 | +# You must obey the GNU General Public License in all respects |
99 | +# for all of the code used other than OpenSSL. If you modify |
100 | +# file(s) with this exception, you may extend this exception to your |
101 | +# version of the file(s), but you are not obligated to do so. If you |
102 | +# do not wish to do so, delete this exception statement from your |
103 | +# version. If you delete this exception statement from all source |
104 | +# files in the program, then also delete it here. |
105 | +"""Custom error types for Ubuntu One developer tools.""" |
106 | + |
107 | + |
108 | +class TestError(Exception): |
109 | + """An error occurred in attempting to load or start the tests.""" |
110 | + |
111 | + |
112 | +class UsageError(Exception): |
113 | + """An error occurred in parsing the command line arguments.""" |
114 | |
115 | === added file 'contrib/devtools/handlers.py' |
116 | --- contrib/devtools/handlers.py 1970-01-01 00:00:00 +0000 |
117 | +++ contrib/devtools/handlers.py 2018-06-03 23:09:20 +0000 |
118 | @@ -0,0 +1,97 @@ |
119 | +# -*- coding: utf-8 -*- |
120 | + |
121 | +# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> |
122 | +# Author: Facundo Batista <facundo@canonical.com> |
123 | +# |
124 | +# Copyright 2009-2012 Canonical Ltd. |
125 | +# |
126 | +# This program is free software: you can redistribute it and/or modify it |
127 | +# under the terms of the GNU General Public License version 3, as published |
128 | +# by the Free Software Foundation. |
129 | +# |
130 | +# This program is distributed in the hope that it will be useful, but |
131 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
132 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
133 | +# PURPOSE. See the GNU General Public License for more details. |
134 | +# |
135 | +# You should have received a copy of the GNU General Public License along |
136 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
137 | +# |
138 | +# In addition, as a special exception, the copyright holders give |
139 | +# permission to link the code of portions of this program with the |
140 | +# OpenSSL library under certain conditions as described in each |
141 | +# individual source file, and distribute linked combinations |
142 | +# including the two. |
143 | +# You must obey the GNU General Public License in all respects |
144 | +# for all of the code used other than OpenSSL. If you modify |
145 | +# file(s) with this exception, you may extend this exception to your |
146 | +# version of the file(s), but you are not obligated to do so. If you |
147 | +# do not wish to do so, delete this exception statement from your |
148 | +# version. If you delete this exception statement from all source |
149 | +# files in the program, then also delete it here. |
150 | +"""Set of helpers handlers.""" |
151 | + |
152 | +from __future__ import print_function |
153 | + |
154 | +import logging |
155 | + |
156 | + |
157 | +class MementoHandler(logging.Handler): |
158 | + """ A handler class which store logging records in a list """ |
159 | + |
160 | + def __init__(self, *args, **kwargs): |
161 | + """ Create the instance, and add a records attribute. """ |
162 | + logging.Handler.__init__(self, *args, **kwargs) |
163 | + self.records = [] |
164 | + self.debug = False |
165 | + |
166 | + def emit(self, record): |
167 | + """ Just add the record to self.records. """ |
168 | + self.format(record) |
169 | + self.records.append(record) |
170 | + |
171 | + def dump_contents(self, msgs): |
172 | + """Dumps the contents of the MementoHandler.""" |
173 | + if self.debug: |
174 | + print("Expecting:") |
175 | + for msg in msgs: |
176 | + print("\t", msg) |
177 | + print("MementoHandler contents:") |
178 | + for rec in self.records: |
179 | + print("\t", rec.exc_info) |
180 | + print("\t", logging.getLevelName(rec.levelno)) |
181 | + print("\t\t", rec.message) |
182 | + print("\t\t", rec.exc_text) |
183 | + |
184 | + def check(self, level, *msgs): |
185 | + """Verifies that the msgs are logged in the specified level""" |
186 | + for rec in self.records: |
187 | + if rec.levelno == level and all(m in rec.message for m in msgs): |
188 | + return rec |
189 | + self.dump_contents(msgs) |
190 | + return False |
191 | + |
192 | + def check_debug(self, *msgs): |
193 | + """Shortcut for checking in DEBUG.""" |
194 | + return self.check(logging.DEBUG, *msgs) |
195 | + |
196 | + def check_info(self, *msgs): |
197 | + """Shortcut for checking in INFO.""" |
198 | + return self.check(logging.INFO, *msgs) |
199 | + |
200 | + def check_warning(self, *msgs): |
201 | + """Shortcut for checking in WARNING.""" |
202 | + return self.check(logging.WARNING, *msgs) |
203 | + |
204 | + def check_error(self, *msgs): |
205 | + """Shortcut for checking in ERROR.""" |
206 | + return self.check(logging.ERROR, *msgs) |
207 | + |
208 | + def check_exception(self, exception_info, *msgs): |
209 | + """Shortcut for checking exceptions.""" |
210 | + for rec in self.records: |
211 | + if rec.levelno == logging.ERROR and \ |
212 | + all(m in rec.exc_text + rec.message for m in msgs) and \ |
213 | + exception_info in rec.exc_info: |
214 | + return True |
215 | + return False |
216 | |
217 | === added directory 'contrib/devtools/reactors' |
218 | === added file 'contrib/devtools/reactors/__init__.py' |
219 | --- contrib/devtools/reactors/__init__.py 1970-01-01 00:00:00 +0000 |
220 | +++ contrib/devtools/reactors/__init__.py 2018-06-03 23:09:20 +0000 |
221 | @@ -0,0 +1,1 @@ |
222 | +"""Twisted reactors for testing.""" |
223 | |
224 | === added file 'contrib/devtools/reactors/gi.py' |
225 | --- contrib/devtools/reactors/gi.py 1970-01-01 00:00:00 +0000 |
226 | +++ contrib/devtools/reactors/gi.py 2018-06-03 23:09:20 +0000 |
227 | @@ -0,0 +1,53 @@ |
228 | +# Copyright 2009-2012 Canonical Ltd. |
229 | +# |
230 | +# This program is free software: you can redistribute it and/or modify it |
231 | +# under the terms of the GNU General Public License version 3, as published |
232 | +# by the Free Software Foundation. |
233 | +# |
234 | +# This program is distributed in the hope that it will be useful, but |
235 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
236 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
237 | +# PURPOSE. See the GNU General Public License for more details. |
238 | +# |
239 | +# You should have received a copy of the GNU General Public License along |
240 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
241 | +# |
242 | +# In addition, as a special exception, the copyright holders give |
243 | +# permission to link the code of portions of this program with the |
244 | +# OpenSSL library under certain conditions as described in each |
245 | +# individual source file, and distribute linked combinations |
246 | +# including the two. |
247 | +# You must obey the GNU General Public License in all respects |
248 | +# for all of the code used other than OpenSSL. If you modify |
249 | +# file(s) with this exception, you may extend this exception to your |
250 | +# version of the file(s), but you are not obligated to do so. If you |
251 | +# do not wish to do so, delete this exception statement from your |
252 | +# version. If you delete this exception statement from all source |
253 | +# files in the program, then also delete it here. |
254 | +"""The introspection based main loop integration reactor for testing.""" |
255 | + |
256 | +REACTOR_URL = 'http://twistedmatrix.com/trac/ticket/4558' |
257 | + |
258 | + |
259 | +def load_reactor(reactor_name=None): |
260 | + """Load the reactor module and return it.""" |
261 | + return __import__(reactor_name, None, None, ['']) |
262 | + |
263 | + |
264 | +def install(options=None): |
265 | + """Install the reactor and parse any options we might need.""" |
266 | + reactor = None |
267 | + if options is not None and options['gui']: |
268 | + try: |
269 | + reactor = load_reactor('twisted.internet.gtk3reactor') |
270 | + except ImportError: |
271 | + print('Falling back to gtk2reactor module.') |
272 | + reactor = load_reactor('twisted.internet.gtk2reactor') |
273 | + else: |
274 | + try: |
275 | + reactor = load_reactor('twisted.internet.gireactor') |
276 | + except ImportError: |
277 | + print('Falling back to glib2reactor module.') |
278 | + reactor = load_reactor('twisted.internet.glib2reactor') |
279 | + |
280 | + reactor.install() |
281 | |
282 | === added directory 'contrib/devtools/runners' |
283 | === added file 'contrib/devtools/runners/__init__.py' |
284 | --- contrib/devtools/runners/__init__.py 1970-01-01 00:00:00 +0000 |
285 | +++ contrib/devtools/runners/__init__.py 2018-06-03 23:09:20 +0000 |
286 | @@ -0,0 +1,305 @@ |
287 | +# Copyright 2009-2012 Canonical Ltd. |
288 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
289 | +# |
290 | +# This program is free software: you can redistribute it and/or modify it |
291 | +# under the terms of the GNU General Public License version 3, as published |
292 | +# by the Free Software Foundation. |
293 | +# |
294 | +# This program is distributed in the hope that it will be useful, but |
295 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
296 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
297 | +# PURPOSE. See the GNU General Public License for more details. |
298 | +# |
299 | +# You should have received a copy of the GNU General Public License along |
300 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
301 | +# |
302 | +# In addition, as a special exception, the copyright holders give |
303 | +# permission to link the code of portions of this program with the |
304 | +# OpenSSL library under certain conditions as described in each |
305 | +# individual source file, and distribute linked combinations |
306 | +# including the two. |
307 | +# You must obey the GNU General Public License in all respects |
308 | +# for all of the code used other than OpenSSL. If you modify |
309 | +# file(s) with this exception, you may extend this exception to your |
310 | +# version of the file(s), but you are not obligated to do so. If you |
311 | +# do not wish to do so, delete this exception statement from your |
312 | +# version. If you delete this exception statement from all source |
313 | +# files in the program, then also delete it here. |
314 | +"""The base test runner object.""" |
315 | + |
316 | +from __future__ import print_function, unicode_literals |
317 | + |
318 | +import coverage |
319 | +import gc |
320 | +import inspect |
321 | +import os |
322 | +import re |
323 | +import sys |
324 | +import unittest |
325 | + |
326 | +from devtools.errors import TestError, UsageError |
327 | +from devtools.testing.txcheck import TXCheckSuite |
328 | +from devtools.utils import OptionParser |
329 | +from devtools.compat import text_type |
330 | + |
331 | +__all__ = ['BaseTestOptions', 'BaseTestRunner', 'main'] |
332 | + |
333 | + |
334 | +def _is_in_ignored_path(testcase, paths): |
335 | + """Return if the testcase is in one of the ignored paths.""" |
336 | + for ignored_path in paths: |
337 | + if testcase.startswith(ignored_path): |
338 | + return True |
339 | + return False |
340 | + |
341 | + |
342 | +class BaseTestRunner(object): |
343 | + """The base test runner type. Does not actually run tests.""" |
344 | + |
345 | + def __init__(self, options=None, *args, **kwargs): |
346 | + super(BaseTestRunner, self).__init__(*args, **kwargs) |
347 | + |
348 | + # set $HOME to the _trial_temp dir, to avoid breaking user files |
349 | + trial_temp_dir = os.environ.get('TRIAL_TEMP_DIR', os.getcwd()) |
350 | + homedir = os.path.join(trial_temp_dir, options['temp-directory']) |
351 | + os.environ['HOME'] = homedir |
352 | + |
353 | + # setup $XDG_*_HOME variables and create the directories |
354 | + xdg_cache = os.path.join(homedir, 'xdg_cache') |
355 | + xdg_config = os.path.join(homedir, 'xdg_config') |
356 | + xdg_data = os.path.join(homedir, 'xdg_data') |
357 | + os.environ['XDG_CACHE_HOME'] = xdg_cache |
358 | + os.environ['XDG_CONFIG_HOME'] = xdg_config |
359 | + os.environ['XDG_DATA_HOME'] = xdg_data |
360 | + |
361 | + if not os.path.exists(xdg_cache): |
362 | + os.makedirs(xdg_cache) |
363 | + if not os.path.exists(xdg_config): |
364 | + os.makedirs(xdg_config) |
365 | + if not os.path.exists(xdg_data): |
366 | + os.makedirs(xdg_data) |
367 | + |
368 | + # setup the ROOTDIR env var |
369 | + os.environ['ROOTDIR'] = os.getcwd() |
370 | + |
371 | + # Need an attribute for tempdir so we can use it later |
372 | + self.tempdir = homedir |
373 | + self.working_dir = os.path.join(self.tempdir, 'trial') |
374 | + |
375 | + self.source_files = [] |
376 | + self.required_services = [] |
377 | + |
378 | + def _load_unittest(self, relpath): |
379 | + """Load unit tests from a Python module with the given 'relpath'.""" |
380 | + assert relpath.endswith(".py"), ( |
381 | + "%s does not appear to be a Python module" % relpath) |
382 | + if not os.path.basename(relpath).startswith('test_'): |
383 | + return |
384 | + modpath = relpath.replace(os.path.sep, ".")[:-3] |
385 | + module = __import__(modpath, None, None, [""]) |
386 | + |
387 | + # If the module specifies required_services, make sure we get them |
388 | + members = [x[1] for x in inspect.getmembers(module, inspect.isclass)] |
389 | + for member_type in members: |
390 | + if hasattr(member_type, 'required_services'): |
391 | + member = member_type() |
392 | + for service in member.required_services(): |
393 | + if service not in self.required_services: |
394 | + self.required_services.append(service) |
395 | + del member |
396 | + gc.collect() |
397 | + |
398 | + # If the module has a 'suite' or 'test_suite' function, use that |
399 | + # to load the tests. |
400 | + if hasattr(module, "suite"): |
401 | + return module.suite() |
402 | + elif hasattr(module, "test_suite"): |
403 | + return module.test_suite() |
404 | + else: |
405 | + return unittest.defaultTestLoader.loadTestsFromModule(module) |
406 | + |
407 | + def _collect_tests(self, path, test_pattern, ignored_modules, |
408 | + ignored_paths): |
409 | + """Return the set of unittests.""" |
410 | + suite = TXCheckSuite() |
411 | + if test_pattern: |
412 | + pattern = re.compile('.*%s.*' % test_pattern) |
413 | + else: |
414 | + pattern = None |
415 | + |
416 | + # Disable this lint warning as we need to access _tests in the |
417 | + # test suites, to collect the tests |
418 | + # pylint: disable=W0212 |
419 | + if path: |
420 | + try: |
421 | + module_suite = self._load_unittest(path) |
422 | + if pattern: |
423 | + for inner_suite in module_suite._tests: |
424 | + for test in inner_suite._tests: |
425 | + if pattern.match(test.id()): |
426 | + suite.addTest(test) |
427 | + else: |
428 | + suite.addTests(module_suite) |
429 | + return suite |
430 | + except AssertionError: |
431 | + pass |
432 | + else: |
433 | + raise TestError('Path should be defined.') |
434 | + |
435 | + # We don't use the dirs variable, so ignore the warning |
436 | + # pylint: disable=W0612 |
437 | + for root, dirs, files in os.walk(path): |
438 | + for test in files: |
439 | + filepath = os.path.join(root, test) |
440 | + if test.endswith(".py") and test not in ignored_modules and \ |
441 | + not _is_in_ignored_path(filepath, ignored_paths): |
442 | + self.source_files.append(filepath) |
443 | + if test.startswith("test_"): |
444 | + module_suite = self._load_unittest(filepath) |
445 | + if pattern: |
446 | + for inner_suite in module_suite._tests: |
447 | + for test in inner_suite._tests: |
448 | + if pattern.match(test.id()): |
449 | + suite.addTest(test) |
450 | + else: |
451 | + suite.addTests(module_suite) |
452 | + return suite |
453 | + |
454 | + def get_suite(self, config): |
455 | + """Get the test suite to use.""" |
456 | + suite = unittest.TestSuite() |
457 | + for path in config['tests']: |
458 | + suite.addTest(self._collect_tests(path, config['test'], |
459 | + config['ignore-modules'], |
460 | + config['ignore-paths'])) |
461 | + if config['loop']: |
462 | + old_suite = suite |
463 | + suite = unittest.TestSuite() |
464 | + for _ in range(config['loop']): |
465 | + suite.addTest(old_suite) |
466 | + |
467 | + return suite |
468 | + |
469 | + def run_tests(self, suite): |
470 | + """Run the test suite.""" |
471 | + return False |
472 | + |
473 | + |
474 | +class BaseTestOptions(OptionParser): |
475 | + """Base options for our test runner.""" |
476 | + |
477 | + optFlags = [['coverage', 'c', 'Generate a coverage report for the tests.'], |
478 | + ['gui', None, 'Use the GUI mode of some runners.'], |
479 | + ['help', 'h', ''], |
480 | + ['help-runners', None, 'List information about test runners.'], |
481 | + ] |
482 | + |
483 | + optParameters = [['test', 't', None, None], |
484 | + ['loop', None, 1, None], |
485 | + ['ignore-modules', 'i', '', None], |
486 | + ['ignore-paths', 'p', '', None], |
487 | + ['runner', None, 'txrunner', None], |
488 | + ['temp-directory', None, b'_trial_temp', None], |
489 | + ] |
490 | + |
491 | + def __init__(self, *args, **kwargs): |
492 | + super(BaseTestOptions, self).__init__(*args, **kwargs) |
493 | + |
494 | + def opt_help_runners(self): |
495 | + """List the runners which are supported.""" |
496 | + sys.exit(0) |
497 | + |
498 | + def opt_ignore_modules(self, option): |
499 | + """Comma-separate list of test modules to ignore, |
500 | + e.g: test_gtk.py, test_account.py |
501 | + """ |
502 | + self['ignore-modules'] = list(map(text_type.strip, option.split(','))) |
503 | + |
504 | + def opt_ignore_paths(self, option): |
505 | + """Comma-separated list of relative paths to ignore, |
506 | + e.g: tests/platform/windows, tests/platform/macosx |
507 | + """ |
508 | + self['ignore-paths'] = list(map(text_type.strip, option.split(','))) |
509 | + |
510 | + def opt_loop(self, option): |
511 | + """Loop tests the specified number of times.""" |
512 | + try: |
513 | + self['loop'] = int(option) |
514 | + except ValueError: |
515 | + raise UsageError('A positive integer value must be specified.') |
516 | + |
517 | + def opt_temp_directory(self, option): |
518 | + """Path to use as a working directory for tests. |
519 | + [default: _trial_temp] |
520 | + """ |
521 | + self['temp-directory'] = option |
522 | + |
523 | + def opt_test(self, option): |
524 | + """Run specific tests, e.g: className.methodName""" |
525 | + self['test'] = option |
526 | + |
527 | + # We use some camelcase names for trial compatibility here. |
528 | + def parseArgs(self, *args): |
529 | + """Handle the extra arguments.""" |
530 | + if isinstance(self.tests, set): |
531 | + self['tests'].update(args) |
532 | + elif isinstance(self.tests, list): |
533 | + self['tests'].extend(args) |
534 | + |
535 | + |
536 | +def _get_runner_options(runner_name): |
537 | + """Return the test runner module, and its options object.""" |
538 | + module_name = 'devtools.runners.%s' % runner_name |
539 | + runner = __import__(module_name, None, None, ['']) |
540 | + options = None |
541 | + if getattr(runner, 'TestOptions', None) is not None: |
542 | + options = runner.TestOptions() |
543 | + if options is None: |
544 | + options = BaseTestOptions() |
545 | + return (runner, options) |
546 | + |
547 | + |
548 | +def main(): |
549 | + """Do the deed.""" |
550 | + if len(sys.argv) == 1: |
551 | + sys.argv.append('--help') |
552 | + |
553 | + try: |
554 | + pos = sys.argv.index('--runner') |
555 | + runner_name = sys.argv.pop(pos + 1) |
556 | + sys.argv.pop(pos) |
557 | + except ValueError: |
558 | + runner_name = 'txrunner' |
559 | + finally: |
560 | + runner, options = _get_runner_options(runner_name) |
561 | + options.parseOptions() |
562 | + |
563 | + test_runner = runner.TestRunner(options=options) |
564 | + suite = test_runner.get_suite(options) |
565 | + |
566 | + if options['coverage']: |
567 | + coverage.erase() |
568 | + coverage.start() |
569 | + |
570 | + running_services = [] |
571 | + |
572 | + succeeded = False |
573 | + try: |
574 | + # Start any required services |
575 | + for service_obj in test_runner.required_services: |
576 | + service = service_obj() |
577 | + service.start_service(tempdir=test_runner.tempdir) |
578 | + running_services.append(service) |
579 | + |
580 | + succeeded = test_runner.run_tests(suite) |
581 | + finally: |
582 | + # Stop all the running services |
583 | + for service in running_services: |
584 | + service.stop_service() |
585 | + |
586 | + if options['coverage']: |
587 | + coverage.stop() |
588 | + coverage.report(test_runner.source_files, ignore_errors=True, |
589 | + show_missing=False) |
590 | + |
591 | + sys.exit(not succeeded) |
592 | |
593 | === added file 'contrib/devtools/runners/txrunner.py' |
594 | --- contrib/devtools/runners/txrunner.py 1970-01-01 00:00:00 +0000 |
595 | +++ contrib/devtools/runners/txrunner.py 2018-06-03 23:09:20 +0000 |
596 | @@ -0,0 +1,133 @@ |
597 | +# Copyright 2009-2012 Canonical Ltd. |
598 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
599 | +# |
600 | +# This program is free software: you can redistribute it and/or modify it |
601 | +# under the terms of the GNU General Public License version 3, as published |
602 | +# by the Free Software Foundation. |
603 | +# |
604 | +# This program is distributed in the hope that it will be useful, but |
605 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
606 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
607 | +# PURPOSE. See the GNU General Public License for more details. |
608 | +# |
609 | +# You should have received a copy of the GNU General Public License along |
610 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
611 | +# |
612 | +# In addition, as a special exception, the copyright holders give |
613 | +# permission to link the code of portions of this program with the |
614 | +# OpenSSL library under certain conditions as described in each |
615 | +# individual source file, and distribute linked combinations |
616 | +# including the two. |
617 | +# You must obey the GNU General Public License in all respects |
618 | +# for all of the code used other than OpenSSL. If you modify |
619 | +# file(s) with this exception, you may extend this exception to your |
620 | +# version of the file(s), but you are not obligated to do so. If you |
621 | +# do not wish to do so, delete this exception statement from your |
622 | +# version. If you delete this exception statement from all source |
623 | +# files in the program, then also delete it here. |
624 | +"""The twisted test runner and options.""" |
625 | + |
626 | +from __future__ import print_function, unicode_literals |
627 | + |
628 | +import sys |
629 | + |
630 | +from twisted.scripts import trial |
631 | +from twisted.trial.runner import TrialRunner |
632 | + |
633 | +from devtools.errors import TestError |
634 | +from devtools.runners import BaseTestOptions, BaseTestRunner |
635 | + |
636 | +__all__ = ['TestRunner', 'TestOptions'] |
637 | + |
638 | + |
639 | +class TestRunner(BaseTestRunner, TrialRunner): |
640 | + """The twisted test runner implementation.""" |
641 | + |
642 | + def __init__(self, options=None): |
643 | + # Handle running trial in debug or dry-run mode |
644 | + self.config = options |
645 | + |
646 | + try: |
647 | + reactor_name = ('devtools.reactors.%s' % (self.config['reactor'],)) |
648 | + reactor = __import__(reactor_name, None, None, ['']) |
649 | + except ImportError: |
650 | + raise TestError('The specified reactor is not supported.') |
651 | + else: |
652 | + try: |
653 | + reactor.install(options=self.config) |
654 | + except ImportError: |
655 | + raise TestError( |
656 | + 'The Python package providing the requested reactor is ' |
657 | + 'not installed. You can find it here: %s' % |
658 | + reactor.REACTOR_URL) |
659 | + |
660 | + mode = None |
661 | + if self.config['debug']: |
662 | + mode = TrialRunner.DEBUG |
663 | + if self.config['dry-run']: |
664 | + mode = TrialRunner.DRY_RUN |
665 | + |
666 | + # Hook up to the parent test runner |
667 | + super(TestRunner, self).__init__( |
668 | + options=options, |
669 | + reporterFactory=self.config['reporter'], |
670 | + mode=mode, |
671 | + profile=self.config['profile'], |
672 | + logfile=self.config['logfile'], |
673 | + tracebackFormat=self.config['tbformat'], |
674 | + realTimeErrors=self.config['rterrors'], |
675 | + uncleanWarnings=self.config['unclean-warnings'], |
676 | + forceGarbageCollection=self.config['force-gc']) |
677 | + # Named for trial compatibility. |
678 | + # pylint: disable=C0103 |
679 | + self.workingDirectory = self.working_dir |
680 | + # pylint: enable=C0103 |
681 | + |
682 | + def run_tests(self, suite): |
683 | + """Run the twisted test suite.""" |
684 | + if self.config['until-failure']: |
685 | + result = self.runUntilFailure(suite) |
686 | + else: |
687 | + result = self.run(suite) |
688 | + return result.wasSuccessful() |
689 | + |
690 | + |
691 | +def _get_default_reactor(): |
692 | + """Return the platform-dependent default reactor to use.""" |
693 | + default_reactor = 'gi' |
694 | + if sys.platform in ['darwin', 'win32']: |
695 | + default_reactor = 'twisted' |
696 | + return default_reactor |
697 | + |
698 | + |
699 | +class TestOptions(trial.Options, BaseTestOptions): |
700 | + """Class for twisted options handling.""" |
701 | + |
702 | + optFlags = [["help-reactors", None], |
703 | + ] |
704 | + |
705 | + optParameters = [["reactor", "r", _get_default_reactor()], |
706 | + ] |
707 | + |
708 | + def __init__(self, *args, **kwargs): |
709 | + super(TestOptions, self).__init__(*args, **kwargs) |
710 | + self['rterrors'] = True |
711 | + |
712 | + def opt_coverage(self, option): |
713 | + """Handle special flags.""" |
714 | + self['coverage'] = True |
715 | + opt_c = opt_coverage |
716 | + |
717 | + def opt_help_reactors(self): |
718 | + """Help on available reactors for use with tests""" |
719 | + synopsis = ('') |
720 | + print(synopsis) |
721 | + print('Need to get list of reactors and print them here.\n') |
722 | + sys.exit(0) |
723 | + |
724 | + def opt_reactor(self, option): |
725 | + """Which reactor to use (see --help-reactors for a list |
726 | + of possibilities) |
727 | + """ |
728 | + self['reactor'] = option |
729 | + opt_r = opt_reactor |
730 | |
731 | === added directory 'contrib/devtools/services' |
732 | === added file 'contrib/devtools/services/__init__.py' |
733 | --- contrib/devtools/services/__init__.py 1970-01-01 00:00:00 +0000 |
734 | +++ contrib/devtools/services/__init__.py 2018-06-03 23:09:20 +0000 |
735 | @@ -0,0 +1,66 @@ |
736 | +# Copyright 2011-2012 Canonical Ltd. |
737 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
738 | +# |
739 | +# This program is free software: you can redistribute it and/or modify it |
740 | +# under the terms of the GNU General Public License version 3, as published |
741 | +# by the Free Software Foundation. |
742 | +# |
743 | +# This program is distributed in the hope that it will be useful, but |
744 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
745 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
746 | +# PURPOSE. See the GNU General Public License for more details. |
747 | +# |
748 | +# You should have received a copy of the GNU General Public License along |
749 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
750 | +# |
751 | +# In addition, as a special exception, the copyright holders give |
752 | +# permission to link the code of portions of this program with the |
753 | +# OpenSSL library under certain conditions as described in each |
754 | +# individual source file, and distribute linked combinations |
755 | +# including the two. |
756 | +# You must obey the GNU General Public License in all respects |
757 | +# for all of the code used other than OpenSSL. If you modify |
758 | +# file(s) with this exception, you may extend this exception to your |
759 | +# version of the file(s), but you are not obligated to do so. If you |
760 | +# do not wish to do so, delete this exception statement from your |
761 | +# version. If you delete this exception statement from all source |
762 | +# files in the program, then also delete it here. |
763 | +"""Service runners for testing.""" |
764 | + |
765 | +import os |
766 | +import socket |
767 | + |
768 | +from dirspec.basedir import load_data_paths |
769 | + |
770 | + |
771 | +def find_config_file(in_config_file): |
772 | + """Find the first appropriate conf to use.""" |
773 | + # In case we're running from within the source tree |
774 | + path = os.path.abspath(os.path.join(os.path.dirname(__file__), |
775 | + os.path.pardir, os.path.pardir, |
776 | + os.path.pardir, |
777 | + "data", in_config_file)) |
778 | + if not os.path.exists(path): |
779 | + # Use the installed file in $pkgdatadir as source |
780 | + for path in load_data_paths("ubuntuone-dev-tools", in_config_file): |
781 | + if os.path.exists(path): |
782 | + break |
783 | + |
784 | + # Check to make sure we didn't just fall out of the loop |
785 | + if not os.path.exists(path): |
786 | + raise IOError('Could not locate suitable %s' % in_config_file) |
787 | + return path |
788 | + |
789 | + |
790 | +def get_arbitrary_port(): |
791 | + """ |
792 | + Find an unused port, and return it. |
793 | + |
794 | + There might be a small race condition here, but we aren't |
795 | + worried about it. |
796 | + """ |
797 | + sock = socket.socket() |
798 | + sock.bind(('localhost', 0)) |
799 | + _, port = sock.getsockname() |
800 | + sock.close() |
801 | + return port |
802 | |
803 | === added file 'contrib/devtools/services/dbus.py' |
804 | --- contrib/devtools/services/dbus.py 1970-01-01 00:00:00 +0000 |
805 | +++ contrib/devtools/services/dbus.py 2018-06-03 23:09:20 +0000 |
806 | @@ -0,0 +1,119 @@ |
807 | +# Copyright 2009-2012 Canonical Ltd. |
808 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
809 | +# |
810 | +# This program is free software: you can redistribute it and/or modify it |
811 | +# under the terms of the GNU General Public License version 3, as published |
812 | +# by the Free Software Foundation. |
813 | +# |
814 | +# This program is distributed in the hope that it will be useful, but |
815 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
816 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
817 | +# PURPOSE. See the GNU General Public License for more details. |
818 | +# |
819 | +# You should have received a copy of the GNU General Public License along |
820 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
821 | +# |
822 | +# In addition, as a special exception, the copyright holders give |
823 | +# permission to link the code of portions of this program with the |
824 | +# OpenSSL library under certain conditions as described in each |
825 | +# individual source file, and distribute linked combinations |
826 | +# including the two. |
827 | +# You must obey the GNU General Public License in all respects |
828 | +# for all of the code used other than OpenSSL. If you modify |
829 | +# file(s) with this exception, you may extend this exception to your |
830 | +# version of the file(s), but you are not obligated to do so. If you |
831 | +# do not wish to do so, delete this exception statement from your |
832 | +# version. If you delete this exception statement from all source |
833 | +# files in the program, then also delete it here. |
834 | +"""Utilities for finding and running a dbus session bus for testing.""" |
835 | + |
836 | +from __future__ import unicode_literals |
837 | + |
838 | +import os |
839 | +import signal |
840 | +import subprocess |
841 | + |
842 | +from distutils.spawn import find_executable |
843 | + |
844 | +# pylint: disable=F0401,E0611 |
845 | +try: |
846 | + from urllib.parse import quote |
847 | +except ImportError: |
848 | + from urllib import quote |
849 | +# pylint: enable=F0401,E0611 |
850 | + |
851 | +from devtools.services import find_config_file |
852 | +DBUS_CONFIG_FILE = 'dbus-session.conf.in' |
853 | + |
854 | + |
855 | +class DBusLaunchError(Exception): |
856 | + """Error while launching dbus-daemon""" |
857 | + pass |
858 | + |
859 | + |
860 | +class NotFoundError(Exception): |
861 | + """Not found error""" |
862 | + pass |
863 | + |
864 | + |
865 | +class DBusRunner(object): |
866 | + """Class for running dbus-daemon with a private session.""" |
867 | + |
868 | + def __init__(self): |
869 | + self.dbus_address = None |
870 | + self.dbus_pid = None |
871 | + self.running = False |
872 | + self.config_file = None |
873 | + |
874 | + def _generate_config_file(self, tempdir=None): |
875 | + """Find the first appropriate dbus-session.conf to use.""" |
876 | + # load the config file |
877 | + path = find_config_file(DBUS_CONFIG_FILE) |
878 | + # replace config settings |
879 | + self.config_file = os.path.join(tempdir, 'dbus-session.conf') |
880 | + dbus_address = 'unix:tmpdir=%s' % quote(tempdir) |
881 | + with open(path) as in_file: |
882 | + content = in_file.read() |
883 | + with open(self.config_file, 'w') as out_file: |
884 | + out_file.write(content.replace('@ADDRESS@', dbus_address)) |
885 | + |
886 | + def start_service(self, tempdir=None): |
887 | + """Start our own session bus daemon for testing.""" |
888 | + dbus = find_executable("dbus-daemon") |
889 | + if not dbus: |
890 | + raise NotFoundError("dbus-daemon was not found.") |
891 | + |
892 | + self._generate_config_file(tempdir) |
893 | + |
894 | + dbus_args = ["--fork", |
895 | + "--config-file=" + self.config_file, |
896 | + "--print-address=1", |
897 | + "--print-pid=2"] |
898 | + sp = subprocess.Popen([dbus] + dbus_args, |
899 | + bufsize=4096, stdout=subprocess.PIPE, |
900 | + stderr=subprocess.PIPE) |
901 | + |
902 | + # Call wait here as under the qt4 reactor we get an error about |
903 | + # interrupted system call if we don't. |
904 | + sp.wait() |
905 | + self.dbus_address = b"".join(sp.stdout.readlines()).strip() |
906 | + self.dbus_pid = int(b"".join(sp.stderr.readlines()).strip()) |
907 | + |
908 | + if self.dbus_address != "": |
909 | + os.environ["DBUS_SESSION_BUS_ADDRESS"] = \ |
910 | + self.dbus_address.decode("utf8") |
911 | + else: |
912 | + os.kill(self.dbus_pid, signal.SIGKILL) |
913 | + raise DBusLaunchError("There was a problem launching dbus-daemon.") |
914 | + self.running = True |
915 | + |
916 | + def stop_service(self): |
917 | + """Stop our DBus session bus daemon.""" |
918 | + try: |
919 | + del os.environ["DBUS_SESSION_BUS_ADDRESS"] |
920 | + except KeyError: |
921 | + pass |
922 | + os.kill(self.dbus_pid, signal.SIGKILL) |
923 | + self.running = False |
924 | + os.unlink(self.config_file) |
925 | + self.config_file = None |
926 | |
927 | === added directory 'contrib/devtools/testcases' |
928 | === added file 'contrib/devtools/testcases/__init__.py' |
929 | --- contrib/devtools/testcases/__init__.py 1970-01-01 00:00:00 +0000 |
930 | +++ contrib/devtools/testcases/__init__.py 2018-06-03 23:09:20 +0000 |
931 | @@ -0,0 +1,187 @@ |
932 | +# -*- coding: utf-8 -*- |
933 | +# |
934 | +# Copyright 2009-2012 Canonical Ltd. |
935 | +# |
936 | +# This program is free software: you can redistribute it and/or modify it |
937 | +# under the terms of the GNU General Public License version 3, as published |
938 | +# by the Free Software Foundation. |
939 | +# |
940 | +# This program is distributed in the hope that it will be useful, but |
941 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
942 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
943 | +# PURPOSE. See the GNU General Public License for more details. |
944 | +# |
945 | +# You should have received a copy of the GNU General Public License along |
946 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
947 | +# |
948 | +# In addition, as a special exception, the copyright holders give |
949 | +# permission to link the code of portions of this program with the |
950 | +# OpenSSL library under certain conditions as described in each |
951 | +# individual source file, and distribute linked combinations |
952 | +# including the two. |
953 | +# You must obey the GNU General Public License in all respects |
954 | +# for all of the code used other than OpenSSL. If you modify |
955 | +# file(s) with this exception, you may extend this exception to your |
956 | +# version of the file(s), but you are not obligated to do so. If you |
957 | +# do not wish to do so, delete this exception statement from your |
958 | +# version. If you delete this exception statement from all source |
959 | +# files in the program, then also delete it here. |
960 | +"""Base tests cases and test utilities.""" |
961 | + |
962 | +from __future__ import with_statement |
963 | + |
964 | +import contextlib |
965 | +import os |
966 | +import shutil |
967 | +import sys |
968 | + |
969 | +from functools import wraps |
970 | + |
971 | +from twisted.trial.unittest import TestCase, SkipTest |
972 | + |
973 | + |
974 | +@contextlib.contextmanager |
975 | +def environ(env_var, new_value): |
976 | + """context manager to replace/add an environ value""" |
977 | + old_value = os.environ.get(env_var, None) |
978 | + os.environ[env_var] = new_value |
979 | + yield |
980 | + if old_value is None: |
981 | + os.environ.pop(env_var) |
982 | + else: |
983 | + os.environ[env_var] = old_value |
984 | + |
985 | + |
986 | +def _id(obj): |
987 | + """Return the obj calling the funct.""" |
988 | + return obj |
989 | + |
990 | + |
991 | +# pylint: disable=C0103 |
992 | +def skipTest(reason): |
993 | + """Unconditionally skip a test.""" |
994 | + |
995 | + def decorator(test_item): |
996 | + """Decorate the test so that it is skipped.""" |
997 | + if not (isinstance(test_item, type) and |
998 | + issubclass(test_item, TestCase)): |
999 | + |
1000 | + @wraps(test_item) |
1001 | + def skip_wrapper(*args, **kwargs): |
1002 | + """Skip a test method raising an exception.""" |
1003 | + raise SkipTest(reason) |
1004 | + test_item = skip_wrapper |
1005 | + |
1006 | + # tell twisted.trial.unittest to skip the test, pylint will complain |
1007 | + # since it thinks we are redefining a name out of the scope |
1008 | + # pylint: disable=W0621,W0612 |
1009 | + test_item.skip = reason |
1010 | + # pylint: enable=W0621,W0612 |
1011 | + # because the item was skipped, we will make sure that no |
1012 | + # services are started for it |
1013 | + if hasattr(test_item, "required_services"): |
1014 | + # pylint: disable=W0612 |
1015 | + test_item.required_services = lambda *args, **kwargs: [] |
1016 | + # pylint: enable=W0612 |
1017 | + return test_item |
1018 | + return decorator |
1019 | + |
1020 | + |
1021 | +def skipIf(condition, reason): |
1022 | + """Skip a test if the condition is true.""" |
1023 | + if condition: |
1024 | + return skipTest(reason) |
1025 | + return _id |
1026 | + |
1027 | + |
1028 | +def skipIfOS(current_os, reason): |
1029 | + """Skip test for a particular os or lists of them.""" |
1030 | + if os: |
1031 | + if sys.platform in current_os or sys.platform == current_os: |
1032 | + return skipTest(reason) |
1033 | + return _id |
1034 | + return _id |
1035 | + |
1036 | + |
1037 | +def skipIfNotOS(current_os, reason): |
1038 | + """Skip test we are not in a particular os.""" |
1039 | + if os: |
1040 | + if sys.platform not in current_os or \ |
1041 | + sys.platform != current_os: |
1042 | + return skipTest(reason) |
1043 | + return _id |
1044 | + return _id |
1045 | + |
1046 | + |
1047 | +def skipIfJenkins(current_os, reason): |
1048 | + """Skip test for a particular os or lists of them |
1049 | + when running on Jenkins.""" |
1050 | + if os.getenv("JENKINS", False) and (sys.platform in current_os or |
1051 | + sys.platform == current_os): |
1052 | + return skipTest(reason) |
1053 | + return _id |
1054 | + |
1055 | + |
1056 | +# pylint: enable=C0103 |
1057 | + |
1058 | + |
1059 | +class BaseTestCase(TestCase): |
1060 | + """Base TestCase with helper methods to handle temp dir. |
1061 | + |
1062 | + This class provides: |
1063 | + mktemp(name): helper to create temporary dirs |
1064 | + rmtree(path): support read-only shares |
1065 | + makedirs(path): support read-only shares |
1066 | + |
1067 | + """ |
1068 | + |
1069 | + def required_services(self): |
1070 | + """Return the list of required services for DBusTestCase.""" |
1071 | + return [] |
1072 | + |
1073 | + def mktemp(self, name='temp'): |
1074 | + """Customized mktemp that accepts an optional name argument.""" |
1075 | + tempdir = os.path.join(self.tmpdir, name) |
1076 | + if os.path.exists(tempdir): |
1077 | + self.rmtree(tempdir) |
1078 | + self.makedirs(tempdir) |
1079 | + return tempdir |
1080 | + |
1081 | + @property |
1082 | + def tmpdir(self): |
1083 | + """Default tmpdir: module/class/test_method.""" |
1084 | + # check if we already generated the root path |
1085 | + root_dir = getattr(self, '__root', None) |
1086 | + if root_dir: |
1087 | + return root_dir |
1088 | + max_filename = 32 # some platforms limit lengths of filenames |
1089 | + base = os.path.join(self.__class__.__module__[:max_filename], |
1090 | + self.__class__.__name__[:max_filename], |
1091 | + self._testMethodName[:max_filename]) |
1092 | + # use _trial_temp dir, it should be os.gwtcwd() |
1093 | + # define the root temp dir of the testcase, pylint: disable=W0201 |
1094 | + self.__root = os.path.join(os.getcwd(), base) |
1095 | + return self.__root |
1096 | + |
1097 | + def rmtree(self, path): |
1098 | + """Custom rmtree that handle ro parent(s) and childs.""" |
1099 | + if not os.path.exists(path): |
1100 | + return |
1101 | + # change perms to rw, so we can delete the temp dir |
1102 | + if path != getattr(self, '__root', None): |
1103 | + os.chmod(os.path.dirname(path), 0o755) |
1104 | + if not os.access(path, os.W_OK): |
1105 | + os.chmod(path, 0o755) |
1106 | + # pylint: disable=W0612 |
1107 | + for dirpath, dirs, files in os.walk(path): |
1108 | + for dirname in dirs: |
1109 | + if not os.access(os.path.join(dirpath, dirname), os.W_OK): |
1110 | + os.chmod(os.path.join(dirpath, dirname), 0o777) |
1111 | + shutil.rmtree(path) |
1112 | + |
1113 | + def makedirs(self, path): |
1114 | + """Custom makedirs that handle ro parent.""" |
1115 | + parent = os.path.dirname(path) |
1116 | + if os.path.exists(parent): |
1117 | + os.chmod(parent, 0o755) |
1118 | + os.makedirs(path) |
1119 | |
1120 | === added file 'contrib/devtools/testcases/dbus.py' |
1121 | --- contrib/devtools/testcases/dbus.py 1970-01-01 00:00:00 +0000 |
1122 | +++ contrib/devtools/testcases/dbus.py 2018-06-03 23:09:20 +0000 |
1123 | @@ -0,0 +1,138 @@ |
1124 | +# -*- coding: utf-8 -*- |
1125 | +# Copyright 2009-2012 Canonical Ltd. |
1126 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
1127 | +# |
1128 | +# This program is free software: you can redistribute it and/or modify it |
1129 | +# under the terms of the GNU General Public License version 3, as published |
1130 | +# by the Free Software Foundation. |
1131 | +# |
1132 | +# This program is distributed in the hope that it will be useful, but |
1133 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1134 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1135 | +# PURPOSE. See the GNU General Public License for more details. |
1136 | +# |
1137 | +# You should have received a copy of the GNU General Public License along |
1138 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1139 | +# |
1140 | +# In addition, as a special exception, the copyright holders give |
1141 | +# permission to link the code of portions of this program with the |
1142 | +# OpenSSL library under certain conditions as described in each |
1143 | +# individual source file, and distribute linked combinations |
1144 | +# including the two. |
1145 | +# You must obey the GNU General Public License in all respects |
1146 | +# for all of the code used other than OpenSSL. If you modify |
1147 | +# file(s) with this exception, you may extend this exception to your |
1148 | +# version of the file(s), but you are not obligated to do so. If you |
1149 | +# do not wish to do so, delete this exception statement from your |
1150 | +# version. If you delete this exception statement from all source |
1151 | +# files in the program, then also delete it here. |
1152 | +"""Base dbus tests cases and test utilities.""" |
1153 | + |
1154 | +from __future__ import absolute_import, with_statement |
1155 | + |
1156 | +import os |
1157 | + |
1158 | +from twisted.internet import defer |
1159 | + |
1160 | +from devtools.testcases import BaseTestCase, skipIf |
1161 | + |
1162 | +# DBusRunner for DBusTestCase using tests |
1163 | +from devtools.services.dbus import DBusRunner |
1164 | + |
1165 | + |
1166 | +# pylint: disable=F0401,C0103,W0406,E0611 |
1167 | +try: |
1168 | + import dbus |
1169 | +except ImportError as e: |
1170 | + dbus = None |
1171 | + |
1172 | +try: |
1173 | + import dbus.service as service |
1174 | +except ImportError: |
1175 | + service = None |
1176 | + |
1177 | +try: |
1178 | + from dbus.mainloop.glib import DBusGMainLoop |
1179 | +except ImportError: |
1180 | + DBusGMainLoop = None |
1181 | + |
1182 | +# pylint: enable=F0401,C0103,W0406,E0611 |
1183 | + |
1184 | + |
1185 | +class InvalidSessionBus(Exception): |
1186 | + """Error when we are connected to the wrong session bus in tests.""" |
1187 | + |
1188 | + |
1189 | +class FakeDBusInterface(object): |
1190 | + """A fake DBusInterface...""" |
1191 | + |
1192 | + def shutdown(self, with_restart=False): |
1193 | + """...that only knows how to go away""" |
1194 | + |
1195 | + |
1196 | +@skipIf(dbus is None or service is None or DBusGMainLoop is None, |
1197 | + "The test requires dbus.") |
1198 | +class DBusTestCase(BaseTestCase): |
1199 | + """Test the DBus event handling.""" |
1200 | + |
1201 | + def required_services(self): |
1202 | + """Return the list of required services for DBusTestCase.""" |
1203 | + services = super(DBusTestCase, self).required_services() |
1204 | + services.extend([DBusRunner]) |
1205 | + return services |
1206 | + |
1207 | + @defer.inlineCallbacks |
1208 | + def setUp(self): |
1209 | + """Setup the infrastructure fo the test (dbus service).""" |
1210 | + # Class 'BaseTestCase' has no 'setUp' member |
1211 | + # pylint: disable=E1101 |
1212 | + # dbus modules will be imported by the decorator |
1213 | + # pylint: disable=E0602 |
1214 | + yield super(DBusTestCase, self).setUp() |
1215 | + |
1216 | + # We need to ensure DBUS_SESSION_BUS_ADDRESS is private here |
1217 | + # pylint: disable=F0401,E0611 |
1218 | + try: |
1219 | + from urllib.parse import unquote |
1220 | + except ImportError: |
1221 | + from urllib import unquote |
1222 | + # pylint: enable=F0401,E0611 |
1223 | + |
1224 | + bus_address = os.environ.get('DBUS_SESSION_BUS_ADDRESS', None) |
1225 | + if os.path.dirname(unquote(bus_address.split(',')[0].split('=')[1])) \ |
1226 | + != os.path.dirname(os.getcwd()): |
1227 | + raise InvalidSessionBus('DBUS_SESSION_BUS_ADDRESS is wrong.') |
1228 | + |
1229 | + # Set up the main loop and bus connection |
1230 | + self.loop = DBusGMainLoop(set_as_default=True) |
1231 | + |
1232 | + # NOTE: The address_or_type value must remain explicitly as |
1233 | + # str instead of anything from devtools.compat. dbus |
1234 | + # expects this to be str regardless of version. |
1235 | + self.bus = dbus.bus.BusConnection(address_or_type=str(bus_address), |
1236 | + mainloop=self.loop) |
1237 | + |
1238 | + # Monkeypatch the dbus.SessionBus/SystemBus methods, to ensure we |
1239 | + # always point at our own private bus instance. |
1240 | + self.patch(dbus, 'SessionBus', lambda: self.bus) |
1241 | + self.patch(dbus, 'SystemBus', lambda: self.bus) |
1242 | + |
1243 | + # Check that we are on the correct bus for real |
1244 | +# Disable this for now, because our tests are extremely broken :( |
1245 | +# bus_names = self.bus.list_names() |
1246 | +# if len(bus_names) > 2: |
1247 | +# raise InvalidSessionBus('Too many bus connections: %s (%r)' % |
1248 | +# (len(bus_names), bus_names)) |
1249 | + |
1250 | + # monkeypatch busName.__del__ to avoid errors on gc |
1251 | + # we take care of releasing the name in shutdown |
1252 | + service.BusName.__del__ = lambda _: None |
1253 | + yield self.bus.set_exit_on_disconnect(False) |
1254 | + self.signal_receivers = set() |
1255 | + |
1256 | + @defer.inlineCallbacks |
1257 | + def tearDown(self): |
1258 | + """Cleanup the test.""" |
1259 | + yield self.bus.flush() |
1260 | + yield self.bus.close() |
1261 | + yield super(DBusTestCase, self).tearDown() |
1262 | |
1263 | === added file 'contrib/devtools/testcases/txsocketserver.py' |
1264 | --- contrib/devtools/testcases/txsocketserver.py 1970-01-01 00:00:00 +0000 |
1265 | +++ contrib/devtools/testcases/txsocketserver.py 2018-06-03 23:09:20 +0000 |
1266 | @@ -0,0 +1,358 @@ |
1267 | +# -*- coding: utf-8 -*- |
1268 | +# Copyright 2012 Canonical Ltd. |
1269 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
1270 | +# |
1271 | +# This program is free software: you can redistribute it and/or modify it |
1272 | +# under the terms of the GNU General Public License version 3, as published |
1273 | +# by the Free Software Foundation. |
1274 | +# |
1275 | +# This program is distributed in the hope that it will be useful, but |
1276 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1277 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1278 | +# PURPOSE. See the GNU General Public License for more details. |
1279 | +# |
1280 | +# You should have received a copy of the GNU General Public License along |
1281 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1282 | +# |
1283 | +# In addition, as a special exception, the copyright holders give |
1284 | +# permission to link the code of portions of this program with the |
1285 | +# OpenSSL library under certain conditions as described in each |
1286 | +# individual source file, and distribute linked combinations |
1287 | +# including the two. |
1288 | +# You must obey the GNU General Public License in all respects |
1289 | +# for all of the code used other than OpenSSL. If you modify |
1290 | +# file(s) with this exception, you may extend this exception to your |
1291 | +# version of the file(s), but you are not obligated to do so. If you |
1292 | +# do not wish to do so, delete this exception statement from your |
1293 | +# version. If you delete this exception statement from all source |
1294 | +# files in the program, then also delete it here. |
1295 | + |
1296 | +"""Base test case for twisted servers.""" |
1297 | + |
1298 | +import os |
1299 | +import shutil |
1300 | +import tempfile |
1301 | + |
1302 | +from twisted.internet import defer, endpoints, protocol |
1303 | +from twisted.spread import pb |
1304 | + |
1305 | +from devtools.testcases import BaseTestCase |
1306 | + |
1307 | +# no init method + twisted common warnings |
1308 | +# pylint: disable=W0232, C0103, E1101 |
1309 | + |
1310 | + |
1311 | +def server_protocol_factory(cls): |
1312 | + """Factory to create tidy protocols.""" |
1313 | + |
1314 | + if cls is None: |
1315 | + cls = protocol.Protocol |
1316 | + |
1317 | + class ServerTidyProtocol(cls): |
1318 | + """A tidy protocol.""" |
1319 | + |
1320 | + def connectionLost(self, *args): |
1321 | + """Lost the connection.""" |
1322 | + cls.connectionLost(self, *args) |
1323 | + # lets tell everyone |
1324 | + # pylint: disable=W0212 |
1325 | + if (self.factory._disconnecting and |
1326 | + self.factory.testserver_on_connection_lost is not None and |
1327 | + not self.factory.testserver_on_connection_lost.called): |
1328 | + self.factory.testserver_on_connection_lost.callback(self) |
1329 | + # pylint: enable=W0212 |
1330 | + |
1331 | + return ServerTidyProtocol |
1332 | + |
1333 | + |
1334 | +def server_factory_factory(cls): |
1335 | + """Factory that creates special types of factories for tests.""" |
1336 | + |
1337 | + if cls is None: |
1338 | + cls = protocol.ServerFactory |
1339 | + |
1340 | + class TidyServerFactory(cls): |
1341 | + """A tidy factory.""" |
1342 | + |
1343 | + testserver_on_connection_lost = None |
1344 | + |
1345 | + def buildProtocol(self, addr): |
1346 | + prot = cls.buildProtocol(self, addr) |
1347 | + self.testserver_on_connection_lost = defer.Deferred() |
1348 | + return prot |
1349 | + |
1350 | + return TidyServerFactory |
1351 | + |
1352 | + |
1353 | +def client_protocol_factory(cls): |
1354 | + """Factory to create tidy protocols.""" |
1355 | + |
1356 | + if cls is None: |
1357 | + cls = protocol.Protocol |
1358 | + |
1359 | + class ClientTidyProtocol(cls): |
1360 | + """A tidy protocol.""" |
1361 | + |
1362 | + def connectionLost(self, *a): |
1363 | + """Connection list.""" |
1364 | + cls.connectionLost(self, *a) |
1365 | + # pylint: disable=W0212 |
1366 | + if (self.factory._disconnecting and |
1367 | + self.factory.testserver_on_connection_lost is not None and |
1368 | + not self.factory.testserver_on_connection_lost.called): |
1369 | + self.factory.testserver_on_connection_lost.callback(self) |
1370 | + # pylint: enable=W0212 |
1371 | + |
1372 | + return ClientTidyProtocol |
1373 | + |
1374 | + |
1375 | +class TidySocketServer(object): |
1376 | + """Ensure that twisted servers are correctly managed in tests. |
1377 | + |
1378 | + Closing a twisted server is a complicated matter. In order to do so you |
1379 | + have to ensure that three different deferreds are fired: |
1380 | + |
1381 | + 1. The server must stop listening. |
1382 | + 2. The client connection must disconnect. |
1383 | + 3. The server connection must disconnect. |
1384 | + |
1385 | + This class allows to create a server and a client that will ensure that |
1386 | + the reactor is left clean by following the pattern described at |
1387 | + http://mumak.net/stuff/twisted-disconnect.html |
1388 | + """ |
1389 | + def __init__(self): |
1390 | + """Create a new instance.""" |
1391 | + self.listener = None |
1392 | + self.server_factory = None |
1393 | + |
1394 | + self.connector = None |
1395 | + self.client_factory = None |
1396 | + |
1397 | + def get_server_endpoint(self): |
1398 | + """Return the server endpoint description.""" |
1399 | + raise NotImplementedError('To be implemented by child classes.') |
1400 | + |
1401 | + def get_client_endpoint(self): |
1402 | + """Return the client endpoint description.""" |
1403 | + raise NotImplementedError('To be implemented by child classes.') |
1404 | + |
1405 | + @defer.inlineCallbacks |
1406 | + def listen_server(self, server_class, *args, **kwargs): |
1407 | + """Start a server in a random port.""" |
1408 | + from twisted.internet import reactor |
1409 | + tidy_class = server_factory_factory(server_class) |
1410 | + self.server_factory = tidy_class(*args, **kwargs) |
1411 | + self.server_factory._disconnecting = False |
1412 | + self.server_factory.protocol = server_protocol_factory( |
1413 | + self.server_factory.protocol) |
1414 | + endpoint = endpoints.serverFromString(reactor, |
1415 | + self.get_server_endpoint()) |
1416 | + self.listener = yield endpoint.listen(self.server_factory) |
1417 | + defer.returnValue(self.server_factory) |
1418 | + |
1419 | + @defer.inlineCallbacks |
1420 | + def connect_client(self, client_class, *args, **kwargs): |
1421 | + """Conect a client to a given server.""" |
1422 | + from twisted.internet import reactor |
1423 | + |
1424 | + if self.server_factory is None: |
1425 | + raise ValueError('Server Factory was not provided.') |
1426 | + if self.listener is None: |
1427 | + raise ValueError('%s has not started listening.', |
1428 | + self.server_factory) |
1429 | + |
1430 | + self.client_factory = client_class(*args, **kwargs) |
1431 | + self.client_factory._disconnecting = False |
1432 | + self.client_factory.protocol = client_protocol_factory( |
1433 | + self.client_factory.protocol) |
1434 | + self.client_factory.testserver_on_connection_lost = defer.Deferred() |
1435 | + endpoint = endpoints.clientFromString(reactor, |
1436 | + self.get_client_endpoint()) |
1437 | + self.connector = yield endpoint.connect(self.client_factory) |
1438 | + defer.returnValue(self.client_factory) |
1439 | + |
1440 | + def clean_up(self): |
1441 | + """Action to be performed for clean up.""" |
1442 | + if self.server_factory is None or self.listener is None: |
1443 | + # nothing to clean |
1444 | + return defer.succeed(None) |
1445 | + |
1446 | + if self.listener and self.connector: |
1447 | + # clean client and server |
1448 | + self.server_factory._disconnecting = True |
1449 | + self.client_factory._disconnecting = True |
1450 | + d = defer.maybeDeferred(self.listener.stopListening) |
1451 | + self.connector.transport.loseConnection() |
1452 | + if self.server_factory.testserver_on_connection_lost: |
1453 | + return defer.gatherResults( |
1454 | + [d, |
1455 | + self.client_factory.testserver_on_connection_lost, |
1456 | + self.server_factory.testserver_on_connection_lost]) |
1457 | + else: |
1458 | + return defer.gatherResults( |
1459 | + [d, |
1460 | + self.client_factory.testserver_on_connection_lost]) |
1461 | + if self.listener: |
1462 | + # just clean the server since there is no client |
1463 | + # pylint: disable=W0201 |
1464 | + self.server_factory._disconnecting = True |
1465 | + return defer.maybeDeferred(self.listener.stopListening) |
1466 | + # pylint: enable=W0201 |
1467 | + |
1468 | + |
1469 | +class TidyTCPServer(TidySocketServer): |
1470 | + """A tidy tcp domain sockets server.""" |
1471 | + |
1472 | + client_endpoint_pattern = 'tcp:host=127.0.0.1:port=%s' |
1473 | + server_endpoint_pattern = 'tcp:0:interface=127.0.0.1' |
1474 | + |
1475 | + def get_server_endpoint(self): |
1476 | + """Return the server endpoint description.""" |
1477 | + return self.server_endpoint_pattern |
1478 | + |
1479 | + def get_client_endpoint(self): |
1480 | + """Return the client endpoint description.""" |
1481 | + if self.server_factory is None: |
1482 | + raise ValueError('Server Factory was not provided.') |
1483 | + if self.listener is None: |
1484 | + raise ValueError('%s has not started listening.', |
1485 | + self.server_factory) |
1486 | + return self.client_endpoint_pattern % self.listener.getHost().port |
1487 | + |
1488 | + |
1489 | +class TidyUnixServer(TidySocketServer): |
1490 | + """A tidy unix domain sockets server.""" |
1491 | + |
1492 | + client_endpoint_pattern = 'unix:path=%s' |
1493 | + server_endpoint_pattern = 'unix:%s' |
1494 | + |
1495 | + def __init__(self): |
1496 | + """Create a new instance.""" |
1497 | + super(TidyUnixServer, self).__init__() |
1498 | + self.temp_dir = tempfile.mkdtemp() |
1499 | + self.path = os.path.join(self.temp_dir, 'tidy_unix_server') |
1500 | + |
1501 | + def get_server_endpoint(self): |
1502 | + """Return the server endpoint description.""" |
1503 | + return self.server_endpoint_pattern % self.path |
1504 | + |
1505 | + def get_client_endpoint(self): |
1506 | + """Return the client endpoint description.""" |
1507 | + return self.client_endpoint_pattern % self.path |
1508 | + |
1509 | + def clean_up(self): |
1510 | + """Action to be performed for clean up.""" |
1511 | + result = super(TidyUnixServer, self).clean_up() |
1512 | + # remove the dir once we are disconnected |
1513 | + result.addCallback(lambda _: shutil.rmtree(self.temp_dir)) |
1514 | + return result |
1515 | + |
1516 | + |
1517 | +class ServerTestCase(BaseTestCase): |
1518 | + """Base test case for tidy servers.""" |
1519 | + |
1520 | + @defer.inlineCallbacks |
1521 | + def setUp(self): |
1522 | + """Set the diff tests.""" |
1523 | + yield super(ServerTestCase, self).setUp() |
1524 | + |
1525 | + try: |
1526 | + self.server_runner = self.get_server() |
1527 | + except NotImplementedError: |
1528 | + self.server_runner = None |
1529 | + |
1530 | + self.server_factory = None |
1531 | + self.client_factory = None |
1532 | + self.server_disconnected = None |
1533 | + self.client_connected = None |
1534 | + self.client_disconnected = None |
1535 | + self.listener = None |
1536 | + self.connector = None |
1537 | + self.addCleanup(self.tear_down_server_client) |
1538 | + |
1539 | + def get_server(self): |
1540 | + """Return the server to be used to run the tests.""" |
1541 | + raise NotImplementedError('To be implemented by child classes.') |
1542 | + |
1543 | + @defer.inlineCallbacks |
1544 | + def listen_server(self, server_class, *args, **kwargs): |
1545 | + """Listen a server. |
1546 | + |
1547 | + The method takes the server class and the arguments that should be |
1548 | + passed to the server constructor. |
1549 | + """ |
1550 | + self.server_factory = yield self.server_runner.listen_server( |
1551 | + server_class, *args, **kwargs) |
1552 | + self.server_disconnected = \ |
1553 | + self.server_factory.testserver_on_connection_lost |
1554 | + self.listener = self.server_runner.listener |
1555 | + |
1556 | + @defer.inlineCallbacks |
1557 | + def connect_client(self, client_class, *args, **kwargs): |
1558 | + """Connect the client. |
1559 | + |
1560 | + The method takes the client factory class and the arguments that |
1561 | + should be passed to the client constructor. |
1562 | + """ |
1563 | + self.client_factory = yield self.server_runner.connect_client( |
1564 | + client_class, *args, **kwargs) |
1565 | + self.client_disconnected = \ |
1566 | + self.client_factory.testserver_on_connection_lost |
1567 | + self.connector = self.server_runner.connector |
1568 | + |
1569 | + def tear_down_server_client(self): |
1570 | + """Clean the server and client.""" |
1571 | + if self.server_runner: |
1572 | + return self.server_runner.clean_up() |
1573 | + |
1574 | + |
1575 | +class TCPServerTestCase(ServerTestCase): |
1576 | + """Test that uses a single twisted server.""" |
1577 | + |
1578 | + def get_server(self): |
1579 | + """Return the server to be used to run the tests.""" |
1580 | + return TidyTCPServer() |
1581 | + |
1582 | + |
1583 | +class UnixServerTestCase(ServerTestCase): |
1584 | + """Test that uses a single twisted server.""" |
1585 | + |
1586 | + def get_server(self): |
1587 | + """Return the server to be used to run the tests.""" |
1588 | + return TidyUnixServer() |
1589 | + |
1590 | + |
1591 | +class PbServerTestCase(ServerTestCase): |
1592 | + """Test a pb server.""" |
1593 | + |
1594 | + def get_server(self): |
1595 | + """Return the server to be used to run the tests.""" |
1596 | + raise NotImplementedError('To be implemented by child classes.') |
1597 | + |
1598 | + @defer.inlineCallbacks |
1599 | + def listen_server(self, *args, **kwargs): |
1600 | + """Listen a pb server.""" |
1601 | + yield super(PbServerTestCase, self).listen_server(pb.PBServerFactory, |
1602 | + *args, **kwargs) |
1603 | + |
1604 | + @defer.inlineCallbacks |
1605 | + def connect_client(self, *args, **kwargs): |
1606 | + """Connect a pb client.""" |
1607 | + yield super(PbServerTestCase, self).connect_client(pb.PBClientFactory, |
1608 | + *args, **kwargs) |
1609 | + |
1610 | + |
1611 | +class TCPPbServerTestCase(PbServerTestCase): |
1612 | + """Test a pb server over TCP.""" |
1613 | + |
1614 | + def get_server(self): |
1615 | + """Return the server to be used to run the tests.""" |
1616 | + return TidyTCPServer() |
1617 | + |
1618 | + |
1619 | +class UnixPbServerTestCase(PbServerTestCase): |
1620 | + """Test a pb server over Unix domain sockets.""" |
1621 | + |
1622 | + def get_server(self): |
1623 | + """Return the server to be used to run the tests.""" |
1624 | + return TidyUnixServer() |
1625 | |
1626 | === added directory 'contrib/devtools/testing' |
1627 | === added file 'contrib/devtools/testing/__init__.py' |
1628 | --- contrib/devtools/testing/__init__.py 1970-01-01 00:00:00 +0000 |
1629 | +++ contrib/devtools/testing/__init__.py 2018-06-03 23:09:20 +0000 |
1630 | @@ -0,0 +1,1 @@ |
1631 | +"""Testing helpers.""" |
1632 | |
1633 | === added file 'contrib/devtools/testing/txcheck.py' |
1634 | --- contrib/devtools/testing/txcheck.py 1970-01-01 00:00:00 +0000 |
1635 | +++ contrib/devtools/testing/txcheck.py 2018-06-03 23:09:20 +0000 |
1636 | @@ -0,0 +1,381 @@ |
1637 | +# -*- coding: utf-8 -*- |
1638 | + |
1639 | +# Author: Tim Cole <tim.cole@canonical.com> |
1640 | +# |
1641 | +# Copyright 2011-2012 Canonical Ltd. |
1642 | +# |
1643 | +# This program is free software: you can redistribute it and/or modify it |
1644 | +# under the terms of the GNU General Public License version 3, as published |
1645 | +# by the Free Software Foundation. |
1646 | +# |
1647 | +# This program is distributed in the hope that it will be useful, but |
1648 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1649 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1650 | +# PURPOSE. See the GNU General Public License for more details. |
1651 | +# |
1652 | +# You should have received a copy of the GNU General Public License along |
1653 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1654 | +# |
1655 | +# In addition, as a special exception, the copyright holders give |
1656 | +# permission to link the code of portions of this program with the |
1657 | +# OpenSSL library under certain conditions as described in each |
1658 | +# individual source file, and distribute linked combinations |
1659 | +# including the two. |
1660 | +# You must obey the GNU General Public License in all respects |
1661 | +# for all of the code used other than OpenSSL. If you modify |
1662 | +# file(s) with this exception, you may extend this exception to your |
1663 | +# version of the file(s), but you are not obligated to do so. If you |
1664 | +# do not wish to do so, delete this exception statement from your |
1665 | +# version. If you delete this exception statement from all source |
1666 | +# files in the program, then also delete it here. |
1667 | +"""Utilities for performing correctness checks.""" |
1668 | + |
1669 | +import sys |
1670 | +import ast |
1671 | +from inspect import getsource |
1672 | +from textwrap import dedent |
1673 | +from itertools import takewhile |
1674 | +from unittest import TestCase, TestSuite, TestResult |
1675 | + |
1676 | +from twisted.trial.unittest import TestCase as TwistedTestCase |
1677 | + |
1678 | + |
1679 | +def type_to_name(type_obj): |
1680 | + """Return a name for a type.""" |
1681 | + package_name = getattr(type_obj, '__module__', None) |
1682 | + if package_name: |
1683 | + return "%s.%s" % (package_name, type_obj.__name__) |
1684 | + else: |
1685 | + return type_obj.__name__ |
1686 | + |
1687 | + |
1688 | +class Problem(AssertionError): |
1689 | + """An object representing a problem in a method.""" |
1690 | + |
1691 | + def __init__(self, method, test_class, ancestor_class): |
1692 | + """Initialize an instance.""" |
1693 | + super(Problem, self).__init__() |
1694 | + self.method = method |
1695 | + self.test_class = test_class |
1696 | + self.ancestor_class = ancestor_class |
1697 | + |
1698 | + def __eq__(self, other): |
1699 | + """Test equality.""" |
1700 | + return type(self) == type(other) and self.__dict__ == other.__dict__ |
1701 | + |
1702 | + def __ne__(self, other): |
1703 | + """Test inequality.""" |
1704 | + return not (self == other) |
1705 | + |
1706 | + def __hash__(self): |
1707 | + """Return hash.""" |
1708 | + member_hash = 0 |
1709 | + for (key, value) in self.__dict__.items(): |
1710 | + member_hash ^= hash(key) ^ hash(value) |
1711 | + return hash(type(self)) ^ member_hash |
1712 | + |
1713 | + def __str__(self): |
1714 | + """Return a friendlier representation.""" |
1715 | + if self.ancestor_class != self.test_class: |
1716 | + method_string = ("%s in ancestor method %s.%s" % |
1717 | + (type_to_name(self.test_class), |
1718 | + type_to_name(self.ancestor_class), |
1719 | + self.method)) |
1720 | + else: |
1721 | + method_string = ("%s.%s" % |
1722 | + (type_to_name(self.test_class), self.method)) |
1723 | + return ("%s for %s" % (type(self).__name__, method_string)) |
1724 | + |
1725 | + def __repr__(self): |
1726 | + """Return representation string.""" |
1727 | + return "<%s %r>" % (type(self), self.__dict__) |
1728 | + |
1729 | + |
1730 | +class MethodShadowed(Problem): |
1731 | + """Problem when trial's run method is shadowed.""" |
1732 | + |
1733 | + |
1734 | +class SuperResultDiscarded(Problem): |
1735 | + """Problem when callback chains are broken.""" |
1736 | + |
1737 | + |
1738 | +class SuperNotCalled(Problem): |
1739 | + """Problem when super isn't called.""" |
1740 | + |
1741 | + |
1742 | +class MissingInlineCallbacks(Problem): |
1743 | + """Problem when the inlineCallbacks decorator is missing.""" |
1744 | + |
1745 | + |
1746 | +class MissingReturnValue(Problem): |
1747 | + """Problem when there's no return value.""" |
1748 | + |
1749 | + |
1750 | +def match_type(expected_type): |
1751 | + """Return predicate matching nodes of given type.""" |
1752 | + return lambda node: isinstance(node, expected_type) |
1753 | + |
1754 | + |
1755 | +def match_equal(expected_value): |
1756 | + """Return predicate matching nodes equaling the given value.""" |
1757 | + return lambda node: expected_value == node |
1758 | + |
1759 | + |
1760 | +def match_in(expected_values): |
1761 | + """Return predicate matching node if in collection of expected values.""" |
1762 | + return lambda node: node in expected_values |
1763 | + |
1764 | + |
1765 | +def match_not_none(): |
1766 | + """Returns a predicate matching nodes which are not None.""" |
1767 | + return lambda node: node is not None |
1768 | + |
1769 | + |
1770 | +def match_any(*subtests): |
1771 | + """Return short-circuiting predicate matching any given subpredicate.""" |
1772 | + if len(subtests) == 1: |
1773 | + return subtests[0] |
1774 | + else: |
1775 | + |
1776 | + def test(node): |
1777 | + """Try each subtest until we find one that passes.""" |
1778 | + for subtest in subtests: |
1779 | + if subtest(node): |
1780 | + return True |
1781 | + return False |
1782 | + |
1783 | + return test |
1784 | + |
1785 | + |
1786 | +def match_all(*subtests): |
1787 | + """Return short-circuiting predicate matching all given subpredicates.""" |
1788 | + if len(subtests) == 1: |
1789 | + return subtests[0] |
1790 | + else: |
1791 | + |
1792 | + def test(node): |
1793 | + """Try each subtest until we find one that fails.""" |
1794 | + for subtest in subtests: |
1795 | + if not subtest(node): |
1796 | + return False |
1797 | + return True |
1798 | + |
1799 | + return test |
1800 | + |
1801 | + |
1802 | +def match_attr(attr_name, *tests): |
1803 | + """Return predicate matching subpredicates against an attribute value.""" |
1804 | + return lambda node: match_all(*tests)(getattr(node, attr_name)) |
1805 | + |
1806 | + |
1807 | +def match_path(initial_test, *components): |
1808 | + """Return predicate which recurses into the tree via given attributes.""" |
1809 | + components = list(components) |
1810 | + components.reverse() |
1811 | + |
1812 | + def test(node): |
1813 | + return True |
1814 | + |
1815 | + for component in components: |
1816 | + attr_name = component[0] |
1817 | + subtests = component[1:] |
1818 | + test = match_attr(attr_name, match_all(match_all(*subtests), test)) |
1819 | + return match_all(initial_test, test) |
1820 | + |
1821 | + |
1822 | +def match_child(*tests): |
1823 | + """Return predicate which tests any child.""" |
1824 | + subtest = match_all(*tests) |
1825 | + |
1826 | + def test(node): |
1827 | + """Try each child until we find one that matches.""" |
1828 | + for child in ast.iter_child_nodes(node): |
1829 | + if subtest(child): |
1830 | + return True |
1831 | + return False |
1832 | + |
1833 | + return test |
1834 | + |
1835 | + |
1836 | +def match_descendant(subtest, prune): |
1837 | + """Return predicate which tests a node and any descendants.""" |
1838 | + |
1839 | + def test(node): |
1840 | + """Recursively (breadth-first) search for a matching node.""" |
1841 | + for child in ast.iter_child_nodes(node): |
1842 | + if prune(child): |
1843 | + continue |
1844 | + if subtest(child) or test(child): |
1845 | + return True |
1846 | + return False |
1847 | + |
1848 | + return test |
1849 | + |
1850 | + |
1851 | +def matches(node, *tests): |
1852 | + """Convenience function to try predicates on a node.""" |
1853 | + return match_all(*tests)(node) |
1854 | + |
1855 | + |
1856 | +def any_matches(nodes, *tests): |
1857 | + """Convenience function to try predicates on any of a sequence of nodes.""" |
1858 | + test = match_all(*tests) |
1859 | + for node in nodes: |
1860 | + if test(node): |
1861 | + return True |
1862 | + return False |
1863 | + |
1864 | + |
1865 | +def iter_matching_child_nodes(node, *tests): |
1866 | + """Yields every matching child node.""" |
1867 | + test = match_all(*tests) |
1868 | + for child in ast.iter_child_nodes(node): |
1869 | + if test(child): |
1870 | + yield child |
1871 | + |
1872 | + |
1873 | +SETUP_FUNCTION_NAMES = ('setUp', 'tearDown') |
1874 | +SETUP_FUNCTION = match_path(match_type(ast.FunctionDef), |
1875 | + ('name', match_in(SETUP_FUNCTION_NAMES))) |
1876 | + |
1877 | +SUPER = match_path(match_type(ast.Call), |
1878 | + ('func', match_type(ast.Attribute)), |
1879 | + ('value', match_type(ast.Call)), |
1880 | + ('func', match_type(ast.Name)), |
1881 | + ('id', match_equal("super"))) |
1882 | + |
1883 | +BARE_SUPER = match_path(match_type(ast.Expr), |
1884 | + ('value', SUPER)) |
1885 | + |
1886 | +YIELD = match_type(ast.Yield) |
1887 | + |
1888 | +INLINE_CALLBACKS_DECORATOR = \ |
1889 | + match_any(match_path(match_type(ast.Attribute), |
1890 | + ('attr', match_equal('inlineCallbacks'))), |
1891 | + match_path(match_type(ast.Name), |
1892 | + ('id', match_equal('inlineCallbacks')))) |
1893 | + |
1894 | +RETURN_VALUE = \ |
1895 | + match_path(match_type(ast.Return), |
1896 | + ('value', match_not_none())) |
1897 | + |
1898 | +DEFS = match_any(match_type(ast.ClassDef), |
1899 | + match_type(ast.FunctionDef)) |
1900 | + |
1901 | + |
1902 | +def find_problems(class_to_check): |
1903 | + """Check twisted test setup in a given test class.""" |
1904 | + mro = class_to_check.__mro__ |
1905 | + if TwistedTestCase not in mro: |
1906 | + return set() |
1907 | + |
1908 | + problems = set() |
1909 | + |
1910 | + ancestry = takewhile(lambda c: c != TwistedTestCase, mro) |
1911 | + for ancestor_class in ancestry: |
1912 | + if 'run' in ancestor_class.__dict__: |
1913 | + problem = MethodShadowed(method='run', |
1914 | + test_class=class_to_check, |
1915 | + ancestor_class=ancestor_class) |
1916 | + problems.add(problem) |
1917 | + |
1918 | + source = dedent(getsource(ancestor_class)) |
1919 | + tree = ast.parse(source) |
1920 | + # the top level of the tree is a Module |
1921 | + class_node = tree.body[0] |
1922 | + |
1923 | + # Check setUp/tearDown |
1924 | + for def_node in iter_matching_child_nodes(class_node, SETUP_FUNCTION): |
1925 | + if matches(def_node, match_child(BARE_SUPER)): |
1926 | + # Superclass method called, but its result wasn't used |
1927 | + problem = SuperResultDiscarded(method=def_node.name, |
1928 | + test_class=class_to_check, |
1929 | + ancestor_class=ancestor_class) |
1930 | + problems.add(problem) |
1931 | + if not matches(def_node, match_descendant(SUPER, DEFS)): |
1932 | + # The call to the overridden superclass method is missing |
1933 | + problem = SuperNotCalled(method=def_node.name, |
1934 | + test_class=class_to_check, |
1935 | + ancestor_class=ancestor_class) |
1936 | + problems.add(problem) |
1937 | + |
1938 | + decorators = def_node.decorator_list |
1939 | + |
1940 | + if matches(def_node, match_descendant(YIELD, DEFS)): |
1941 | + # Yield was used, making this a generator |
1942 | + if not any_matches(decorators, INLINE_CALLBACKS_DECORATOR): |
1943 | + # ...but the inlineCallbacks decorator is missing |
1944 | + problem = MissingInlineCallbacks( |
1945 | + method=def_node.name, |
1946 | + test_class=class_to_check, |
1947 | + ancestor_class=ancestor_class) |
1948 | + problems.add(problem) |
1949 | + else: |
1950 | + if not matches(def_node, match_descendant(RETURN_VALUE, DEFS)): |
1951 | + # The function fails to return a deferred |
1952 | + problem = MissingReturnValue( |
1953 | + method=def_node.name, |
1954 | + test_class=class_to_check, |
1955 | + ancestor_class=ancestor_class) |
1956 | + problems.add(problem) |
1957 | + |
1958 | + return problems |
1959 | + |
1960 | + |
1961 | +def get_test_classes(suite): |
1962 | + """Return all the unique test classes involved in a suite.""" |
1963 | + classes = set() |
1964 | + |
1965 | + def find_classes(suite_or_test): |
1966 | + """Recursively find all the test classes.""" |
1967 | + if isinstance(suite_or_test, TestSuite): |
1968 | + for subtest in suite_or_test: |
1969 | + find_classes(subtest) |
1970 | + else: |
1971 | + classes.add(type(suite_or_test)) |
1972 | + |
1973 | + find_classes(suite) |
1974 | + |
1975 | + return classes |
1976 | + |
1977 | + |
1978 | +def make_check_testcase(tests): |
1979 | + """Make TestCase which checks the given twisted tests.""" |
1980 | + |
1981 | + class TXCheckTest(TestCase): |
1982 | + """Test case which checks the test classes for problems.""" |
1983 | + |
1984 | + def runTest(self): # pylint: disable=C0103 |
1985 | + """Do nothing.""" |
1986 | + |
1987 | + def run(self, result=None): |
1988 | + """Check all the test classes for problems.""" |
1989 | + if result is None: |
1990 | + result = TestResult() |
1991 | + |
1992 | + test_classes = set() |
1993 | + |
1994 | + for test_object in tests: |
1995 | + test_classes |= get_test_classes(test_object) |
1996 | + |
1997 | + for test_class in test_classes: |
1998 | + problems = find_problems(test_class) |
1999 | + for problem in problems: |
2000 | + try: |
2001 | + raise problem |
2002 | + except Problem: |
2003 | + result.addFailure(self, sys.exc_info()) |
2004 | + |
2005 | + return TXCheckTest() |
2006 | + |
2007 | + |
2008 | +class TXCheckSuite(TestSuite): |
2009 | + """Test suite which checks twisted tests.""" |
2010 | + |
2011 | + def __init__(self, tests=()): |
2012 | + """Initialize with the given tests, and add a special test.""" |
2013 | + |
2014 | + tests = list(tests) |
2015 | + tests.insert(0, make_check_testcase(self)) |
2016 | + |
2017 | + super(TXCheckSuite, self).__init__(tests) |
2018 | |
2019 | === added file 'contrib/devtools/testing/txwebserver.py' |
2020 | --- contrib/devtools/testing/txwebserver.py 1970-01-01 00:00:00 +0000 |
2021 | +++ contrib/devtools/testing/txwebserver.py 2018-06-03 23:09:20 +0000 |
2022 | @@ -0,0 +1,125 @@ |
2023 | +# -*- coding: utf-8 -*- |
2024 | +# Copyright 2012 Canonical Ltd. |
2025 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
2026 | +# |
2027 | +# This program is free software: you can redistribute it and/or modify it |
2028 | +# under the terms of the GNU General Public License version 3, as published |
2029 | +# by the Free Software Foundation. |
2030 | +# |
2031 | +# This program is distributed in the hope that it will be useful, but |
2032 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
2033 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2034 | +# PURPOSE. See the GNU General Public License for more details. |
2035 | +# |
2036 | +# You should have received a copy of the GNU General Public License along |
2037 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
2038 | +# |
2039 | +# In addition, as a special exception, the copyright holders give |
2040 | +# permission to link the code of portions of this program with the |
2041 | +# OpenSSL library under certain conditions as described in each |
2042 | +# individual source file, and distribute linked combinations |
2043 | +# including the two. |
2044 | +# You must obey the GNU General Public License in all respects |
2045 | +# for all of the code used other than OpenSSL. If you modify |
2046 | +# file(s) with this exception, you may extend this exception to your |
2047 | +# version of the file(s), but you are not obligated to do so. If you |
2048 | +# do not wish to do so, delete this exception statement from your |
2049 | +# version. If you delete this exception statement from all source |
2050 | +# files in the program, then also delete it here. |
2051 | + |
2052 | +"""A tx based web server.""" |
2053 | + |
2054 | +from __future__ import unicode_literals |
2055 | + |
2056 | +from twisted.internet import defer, reactor, ssl |
2057 | +from twisted.protocols.policies import WrappingFactory |
2058 | +from twisted.web import server |
2059 | + |
2060 | +from devtools.testcases.txsocketserver import server_protocol_factory |
2061 | + |
2062 | +# no init method + twisted common warnings |
2063 | +# pylint: disable=W0232, C0103, E1101 |
2064 | + |
2065 | + |
2066 | +class BaseWebServer(object): |
2067 | + """Webserver used to perform requests in tests.""" |
2068 | + |
2069 | + def __init__(self, root_resource, scheme): |
2070 | + """Create and start the instance. |
2071 | + |
2072 | + The ssl_settings parameter contains a dictionary with the key and cert |
2073 | + that will be used to perform ssl connections. The root_resource |
2074 | + contains the resource with all its childre. |
2075 | + """ |
2076 | + self.root = root_resource |
2077 | + self.scheme = scheme |
2078 | + self.port = None |
2079 | + # use an http.HTTPFactory that was modified to ensure that we have |
2080 | + # clean close connections |
2081 | + self.site = server.Site(self.root, timeout=None) |
2082 | + self.wrapper = WrappingFactory(self.site) |
2083 | + self.wrapper.testserver_on_connection_lost = defer.Deferred() |
2084 | + self.wrapper.protocol = server_protocol_factory(self.wrapper.protocol) |
2085 | + self.wrapper._disconnecting = False |
2086 | + |
2087 | + def listen(self, site): |
2088 | + """Listen a port to allow the tests.""" |
2089 | + raise NotImplementedError('Base abstract class.') |
2090 | + |
2091 | + def get_iri(self): |
2092 | + """Build the iri for this mock server.""" |
2093 | + return "{scheme}://127.0.0.1:{port}/".format(scheme=self.scheme, |
2094 | + port=self.get_port()) |
2095 | + |
2096 | + def get_port(self): |
2097 | + """Return the port where we are listening.""" |
2098 | + return self.port.getHost().port |
2099 | + |
2100 | + def start(self): |
2101 | + """Start the service.""" |
2102 | + self.port = self.listen(self.wrapper) |
2103 | + |
2104 | + def stop(self): |
2105 | + """Shut it down.""" |
2106 | + if self.port: |
2107 | + self.wrapper._disconnecting = True |
2108 | + connected = self.wrapper.protocols.keys() |
2109 | + if connected: |
2110 | + for con in connected: |
2111 | + con.transport.loseConnection() |
2112 | + else: |
2113 | + self.wrapper.testserver_on_connection_lost = \ |
2114 | + defer.succeed(None) |
2115 | + d = defer.maybeDeferred(self.port.stopListening) |
2116 | + return defer.gatherResults( |
2117 | + [d, |
2118 | + self.wrapper.testserver_on_connection_lost]) |
2119 | + return defer.succeed(None) |
2120 | + |
2121 | + |
2122 | +class HTTPWebServer(BaseWebServer): |
2123 | + """A Webserver that listens to http connections.""" |
2124 | + |
2125 | + def __init__(self, root_resource): |
2126 | + """Create a new instance.""" |
2127 | + super(HTTPWebServer, self).__init__(root_resource, 'http') |
2128 | + |
2129 | + def listen(self, site): |
2130 | + """Listen a port to allow the tests.""" |
2131 | + return reactor.listenTCP(0, site) |
2132 | + |
2133 | + |
2134 | +class HTTPSWebServer(BaseWebServer): |
2135 | + """A WebServer that listens to https connections.""" |
2136 | + |
2137 | + def __init__(self, root_resource, ssl_settings=None): |
2138 | + """Create a new instance.""" |
2139 | + super(HTTPSWebServer, self).__init__(root_resource, 'https') |
2140 | + self.ssl_settings = ssl_settings |
2141 | + |
2142 | + def listen(self, site): |
2143 | + """Listen a port to allow the tests.""" |
2144 | + ssl_context = ssl.DefaultOpenSSLContextFactory( |
2145 | + self.ssl_settings['key'], self.ssl_settings['cert']) |
2146 | + |
2147 | + return reactor.listenSSL(0, site, ssl_context) |
2148 | |
2149 | === added file 'contrib/devtools/utils.py' |
2150 | --- contrib/devtools/utils.py 1970-01-01 00:00:00 +0000 |
2151 | +++ contrib/devtools/utils.py 2018-06-03 23:09:20 +0000 |
2152 | @@ -0,0 +1,181 @@ |
2153 | +# Copyright 2009-2012 Canonical Ltd. |
2154 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
2155 | +# |
2156 | +# This program is free software: you can redistribute it and/or modify it |
2157 | +# under the terms of the GNU General Public License version 3, as published |
2158 | +# by the Free Software Foundation. |
2159 | +# |
2160 | +# This program is distributed in the hope that it will be useful, but |
2161 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
2162 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2163 | +# PURPOSE. See the GNU General Public License for more details. |
2164 | +# |
2165 | +# You should have received a copy of the GNU General Public License along |
2166 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
2167 | +# |
2168 | +# In addition, as a special exception, the copyright holders give |
2169 | +# permission to link the code of portions of this program with the |
2170 | +# OpenSSL library under certain conditions as described in each |
2171 | +# individual source file, and distribute linked combinations |
2172 | +# including the two. |
2173 | +# You must obey the GNU General Public License in all respects |
2174 | +# for all of the code used other than OpenSSL. If you modify |
2175 | +# file(s) with this exception, you may extend this exception to your |
2176 | +# version of the file(s), but you are not obligated to do so. If you |
2177 | +# do not wish to do so, delete this exception statement from your |
2178 | +# version. If you delete this exception statement from all source |
2179 | +# files in the program, then also delete it here. |
2180 | +"""Utilities for Ubuntu One developer tools.""" |
2181 | + |
2182 | +from __future__ import print_function, unicode_literals |
2183 | + |
2184 | +import getopt |
2185 | +import sys |
2186 | + |
2187 | +from devtools.errors import UsageError |
2188 | +__all__ = ['OptionParser'] |
2189 | + |
2190 | + |
2191 | +def accumulate_list_attr(class_obj, attr, list_obj, base_class=None): |
2192 | + """Get all of the list attributes of attr from the class hierarchy, |
2193 | + and return a list of the lists.""" |
2194 | + for base in class_obj.__bases__: |
2195 | + accumulate_list_attr(base, attr, list_obj) |
2196 | + if base_class is None or base_class in class_obj.__bases__: |
2197 | + list_obj.extend(class_obj.__dict__.get(attr, [])) |
2198 | + |
2199 | + |
2200 | +def unpack_padded(length, sequence, default=None): |
2201 | + """Pads a sequence to length with value of default. |
2202 | + |
2203 | + Returns a list containing the original and padded values. |
2204 | + """ |
2205 | + newlist = [default] * length |
2206 | + newlist[:len(sequence)] = list(sequence) |
2207 | + return newlist |
2208 | + |
2209 | + |
2210 | +class OptionParser(dict): |
2211 | + """Base options for our test runner.""" |
2212 | + |
2213 | + def __init__(self, *args, **kwargs): |
2214 | + super(OptionParser, self).__init__(*args, **kwargs) |
2215 | + |
2216 | + # Store info about the options and defaults |
2217 | + self.long_opts = [] |
2218 | + self.short_opts = '' |
2219 | + self.docs = {} |
2220 | + self.defaults = {} |
2221 | + self.synonyms = {} |
2222 | + self.dispatch = {} |
2223 | + |
2224 | + # Get the options and defaults |
2225 | + for _get in [self._get_flags, self._get_params]: |
2226 | + # We don't use variable 'syns' here. It's just to pad the result. |
2227 | + # pylint: disable=W0612 |
2228 | + (long_opts, short_opts, docs, defaults, syns, dispatch) = _get() |
2229 | + # pylint: enable=W0612 |
2230 | + self.long_opts.extend(long_opts) |
2231 | + self.short_opts = self.short_opts + short_opts |
2232 | + self.docs.update(docs) |
2233 | + self.update(defaults) |
2234 | + self.defaults.update(defaults) |
2235 | + self.synonyms.update(syns) |
2236 | + self.dispatch.update(dispatch) |
2237 | + |
2238 | + # We use some camelcase names for trial compatibility here. |
2239 | + # pylint: disable=C0103 |
2240 | + def parseOptions(self, options=None): |
2241 | + """Parse the options.""" |
2242 | + if options is None: |
2243 | + options = sys.argv[1:] |
2244 | + |
2245 | + try: |
2246 | + opts, args = getopt.getopt(options, |
2247 | + self.short_opts, self.long_opts) |
2248 | + except getopt.error as e: |
2249 | + raise UsageError(e) |
2250 | + |
2251 | + for opt, arg in opts: |
2252 | + if opt[1] == '-': |
2253 | + opt = opt[2:] |
2254 | + else: |
2255 | + opt = opt[1:] |
2256 | + |
2257 | + if (opt not in self.synonyms.keys()): |
2258 | + raise UsageError('No such options: "%s"' % opt) |
2259 | + |
2260 | + opt = self.synonyms[opt] |
2261 | + if self.defaults[opt] is False: |
2262 | + self[opt] = True |
2263 | + else: |
2264 | + self.dispatch[opt](arg) |
2265 | + |
2266 | + try: |
2267 | + self.parseArgs(*args) |
2268 | + except TypeError: |
2269 | + raise UsageError('Wrong number of arguments.') |
2270 | + |
2271 | + self.postOptions() |
2272 | + |
2273 | + def postOptions(self): |
2274 | + """Called after options are parsed.""" |
2275 | + |
2276 | + def parseArgs(self, *args): |
2277 | + """Override to handle extra arguments specially.""" |
2278 | + # pylint: enable=C0103 |
2279 | + |
2280 | + def _parse_arguments(self, arg_type=None, has_default=False): |
2281 | + """Parse the arguments as either flags or parameters.""" |
2282 | + long_opts, short_opts = [], '' |
2283 | + docs, defaults, syns, dispatch = {}, {}, {}, {} |
2284 | + |
2285 | + _args = [] |
2286 | + accumulate_list_attr(self.__class__, arg_type, _args) |
2287 | + |
2288 | + for _arg in _args: |
2289 | + try: |
2290 | + if has_default: |
2291 | + l_opt, s_opt, default, doc, _ = unpack_padded(5, _arg) |
2292 | + else: |
2293 | + default = False |
2294 | + l_opt, s_opt, doc, _ = unpack_padded(4, _arg) |
2295 | + except ValueError: |
2296 | + raise ValueError('Failed to parse argument: %s' % _arg) |
2297 | + if not l_opt: |
2298 | + raise ValueError('An option must have a long name.') |
2299 | + |
2300 | + opt_m_name = 'opt_' + l_opt.replace('-', '_') |
2301 | + opt_method = getattr(self, opt_m_name, None) |
2302 | + if opt_method is not None: |
2303 | + docs[l_opt] = getattr(opt_method, '__doc__', None) |
2304 | + dispatch[l_opt] = opt_method |
2305 | + if docs[l_opt] is None: |
2306 | + docs[l_opt] = doc |
2307 | + else: |
2308 | + docs[l_opt] = doc |
2309 | + dispatch[l_opt] = lambda arg: True |
2310 | + |
2311 | + defaults[l_opt] = default |
2312 | + if has_default: |
2313 | + long_opts.append(l_opt + '=') |
2314 | + else: |
2315 | + long_opts.append(l_opt) |
2316 | + |
2317 | + syns[l_opt] = l_opt |
2318 | + if s_opt is not None: |
2319 | + short_opts = short_opts + s_opt |
2320 | + if has_default: |
2321 | + short_opts = short_opts + ':' |
2322 | + syns[s_opt] = l_opt |
2323 | + |
2324 | + return long_opts, short_opts, docs, defaults, syns, dispatch |
2325 | + |
2326 | + def _get_flags(self): |
2327 | + """Get the flag options.""" |
2328 | + return self._parse_arguments(arg_type='optFlags', has_default=False) |
2329 | + |
2330 | + def _get_params(self): |
2331 | + """Get the parameters options.""" |
2332 | + return self._parse_arguments(arg_type='optParameters', |
2333 | + has_default=True) |
2334 | |
2335 | === added directory 'contrib/dirspec' |
2336 | === added file 'contrib/dirspec/__init__.py' |
2337 | --- contrib/dirspec/__init__.py 1970-01-01 00:00:00 +0000 |
2338 | +++ contrib/dirspec/__init__.py 2018-06-03 23:09:20 +0000 |
2339 | @@ -0,0 +1,16 @@ |
2340 | +# -*- coding: utf-8 -*- |
2341 | +# |
2342 | +# Copyright 2011 Canonical Ltd. |
2343 | +# |
2344 | +# This program is free software: you can redistribute it and/or modify |
2345 | +# it under the terms of the GNU Lesser General Public License version 3 |
2346 | +# as published by the Free Software Foundation. |
2347 | +# |
2348 | +# This program is distributed in the hope that it will be useful, |
2349 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2350 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2351 | +# GNU Lesser General Public License for more details. |
2352 | +# |
2353 | +# You should have received a copy of the GNU Lesser General Public License |
2354 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2355 | +"""dirspec package.""" |
2356 | |
2357 | === added file 'contrib/dirspec/basedir.py' |
2358 | --- contrib/dirspec/basedir.py 1970-01-01 00:00:00 +0000 |
2359 | +++ contrib/dirspec/basedir.py 2018-06-03 23:09:20 +0000 |
2360 | @@ -0,0 +1,159 @@ |
2361 | +# -*- coding: utf-8 -*- |
2362 | +# |
2363 | +# Copyright 2011-2012 Canonical Ltd. |
2364 | +# |
2365 | +# This program is free software: you can redistribute it and/or modify |
2366 | +# it under the terms of the GNU Lesser General Public License version 3 |
2367 | +# as published by the Free Software Foundation. |
2368 | +# |
2369 | +# This program is distributed in the hope that it will be useful, |
2370 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2371 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2372 | +# GNU Lesser General Public License for more details. |
2373 | +# |
2374 | +# You should have received a copy of the GNU Lesser General Public License |
2375 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2376 | +"""XDG Base Directory paths.""" |
2377 | + |
2378 | +from __future__ import unicode_literals, print_function |
2379 | + |
2380 | +import os |
2381 | + |
2382 | +from dirspec.utils import (default_cache_home, |
2383 | + default_config_path, default_config_home, |
2384 | + default_data_path, default_data_home, |
2385 | + get_env_path, unicode_path) |
2386 | + |
2387 | +__all__ = ['xdg_cache_home', |
2388 | + 'xdg_config_home', |
2389 | + 'xdg_data_home', |
2390 | + 'xdg_config_dirs', |
2391 | + 'xdg_data_dirs', |
2392 | + 'load_config_paths', |
2393 | + 'load_data_paths', |
2394 | + 'load_first_config', |
2395 | + 'save_config_path', |
2396 | + 'save_data_path', |
2397 | + ] |
2398 | + |
2399 | + |
2400 | +def get_xdg_cache_home(): |
2401 | + """Get the path for XDG cache directory in user's HOME.""" |
2402 | + return get_env_path('XDG_CACHE_HOME', default_cache_home) |
2403 | + |
2404 | + |
2405 | +def get_xdg_config_home(): |
2406 | + """Get the path for XDG config directory in user's HOME.""" |
2407 | + return get_env_path('XDG_CONFIG_HOME', default_config_home) |
2408 | + |
2409 | + |
2410 | +def get_xdg_data_home(): |
2411 | + """Get the path for XDG data directory in user's HOME.""" |
2412 | + return get_env_path('XDG_DATA_HOME', default_data_home) |
2413 | + |
2414 | + |
2415 | +def get_xdg_config_dirs(): |
2416 | + """Get the paths for the XDG config directories.""" |
2417 | + result = [get_xdg_config_home()] |
2418 | + result.extend([x.encode('utf-8') for x in get_env_path( |
2419 | + 'XDG_CONFIG_DIRS', |
2420 | + default_config_path).decode('utf-8').split(os.pathsep)]) |
2421 | + return result |
2422 | + |
2423 | + |
2424 | +def get_xdg_data_dirs(): |
2425 | + """Get the paths for the XDG data directories.""" |
2426 | + result = [get_xdg_data_home()] |
2427 | + result.extend([x.encode('utf-8') for x in get_env_path( |
2428 | + 'XDG_DATA_DIRS', |
2429 | + default_data_path).decode('utf-8').split(os.pathsep)]) |
2430 | + return result |
2431 | + |
2432 | + |
2433 | +def load_config_paths(*resource): |
2434 | + """Iterator of configuration paths. |
2435 | + |
2436 | + Return an iterator which gives each directory named 'resource' in |
2437 | + the configuration search path. Information provided by earlier |
2438 | + directories should take precedence over later ones (ie, the user's |
2439 | + config dir comes first). |
2440 | + """ |
2441 | + resource = os.path.join(*resource) |
2442 | + assert not resource.startswith('/') |
2443 | + for config_dir in get_xdg_config_dirs(): |
2444 | + path = os.path.join(config_dir, resource.encode('utf-8')) |
2445 | + # access the file system always with unicode |
2446 | + # to properly behave in some operating systems |
2447 | + if os.path.exists(unicode_path(path)): |
2448 | + yield path |
2449 | + |
2450 | + |
2451 | +def load_data_paths(*resource): |
2452 | + """Iterator of data paths. |
2453 | + |
2454 | + Return an iterator which gives each directory named 'resource' in |
2455 | + the stored data search path. Information provided by earlier |
2456 | + directories should take precedence over later ones. |
2457 | + """ |
2458 | + resource = os.path.join(*resource) |
2459 | + assert not resource.startswith('/') |
2460 | + for data_dir in get_xdg_data_dirs(): |
2461 | + path = os.path.join(data_dir, resource.encode('utf-8')) |
2462 | + # access the file system always with unicode |
2463 | + # to properly behave in some operating systems |
2464 | + if os.path.exists(unicode_path(path)): |
2465 | + yield path |
2466 | + |
2467 | + |
2468 | +def load_first_config(*resource): |
2469 | + """Returns the first result from load_config_paths, or None if nothing |
2470 | + is found to load. |
2471 | + """ |
2472 | + for path in load_config_paths(*resource): |
2473 | + return path |
2474 | + return None |
2475 | + |
2476 | + |
2477 | +def save_config_path(*resource): |
2478 | + """Path to save configuration. |
2479 | + |
2480 | + Ensure $XDG_CONFIG_HOME/<resource>/ exists, and return its path. |
2481 | + 'resource' should normally be the name of your application. Use this |
2482 | + when SAVING configuration settings. Use the xdg_config_dirs variable |
2483 | + for loading. |
2484 | + """ |
2485 | + resource = os.path.join(*resource) |
2486 | + assert not resource.startswith('/') |
2487 | + path = os.path.join(get_xdg_config_home(), resource.encode('utf-8')) |
2488 | + # access the file system always with unicode |
2489 | + # to properly behave in some operating systems |
2490 | + if not os.path.isdir(unicode_path(path)): |
2491 | + os.makedirs(unicode_path(path), 0o700) |
2492 | + return path |
2493 | + |
2494 | + |
2495 | +def save_data_path(*resource): |
2496 | + """Path to save data. |
2497 | + |
2498 | + Ensure $XDG_DATA_HOME/<resource>/ exists, and return its path. |
2499 | + 'resource' should normally be the name of your application. Use this |
2500 | + when STORING a resource. Use the xdg_data_dirs variable for loading. |
2501 | + """ |
2502 | + resource = os.path.join(*resource) |
2503 | + assert not resource.startswith('/') |
2504 | + path = os.path.join(get_xdg_data_home(), resource.encode('utf-8')) |
2505 | + # access the file system always with unicode |
2506 | + # to properly behave in some operating systems |
2507 | + if not os.path.isdir(unicode_path(path)): |
2508 | + os.makedirs(unicode_path(path), 0o700) |
2509 | + return path |
2510 | + |
2511 | + |
2512 | +# pylint: disable=C0103 |
2513 | +xdg_cache_home = get_xdg_cache_home() |
2514 | +xdg_config_home = get_xdg_config_home() |
2515 | +xdg_data_home = get_xdg_data_home() |
2516 | + |
2517 | +xdg_config_dirs = [x for x in get_xdg_config_dirs() if x] |
2518 | +xdg_data_dirs = [x for x in get_xdg_data_dirs() if x] |
2519 | +# pylint: disable=C0103 |
2520 | |
2521 | === added file 'contrib/dirspec/utils.py' |
2522 | --- contrib/dirspec/utils.py 1970-01-01 00:00:00 +0000 |
2523 | +++ contrib/dirspec/utils.py 2018-06-03 23:09:20 +0000 |
2524 | @@ -0,0 +1,188 @@ |
2525 | +# -*- coding: utf-8 -*- |
2526 | +# |
2527 | +# Copyright 2011-2012 Canonical Ltd. |
2528 | +# |
2529 | +# This program is free software: you can redistribute it and/or modify |
2530 | +# it under the terms of the GNU Lesser General Public License version 3 |
2531 | +# as published by the Free Software Foundation. |
2532 | +# |
2533 | +# This program is distributed in the hope that it will be useful, |
2534 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2535 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2536 | +# GNU Lesser General Public License for more details. |
2537 | +# |
2538 | +# You should have received a copy of the GNU Lesser General Public License |
2539 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2540 | +"""Utilities for multiplatform support of XDG directory handling.""" |
2541 | + |
2542 | +from __future__ import unicode_literals, print_function |
2543 | + |
2544 | +import errno |
2545 | +import os |
2546 | +import sys |
2547 | + |
2548 | +__all__ = ['user_home', |
2549 | + 'default_cache_home', |
2550 | + 'default_config_home', |
2551 | + 'default_config_path', |
2552 | + 'default_data_home', |
2553 | + 'default_data_path', |
2554 | + 'get_env_path', |
2555 | + 'get_program_path', |
2556 | + 'unicode_path', |
2557 | + ] |
2558 | + |
2559 | + |
2560 | +def _get_exe_path_frozen_win32(exe_name): |
2561 | + """Get path to the helper .exe on packaged windows.""" |
2562 | + # all the .exes are in the same place on windows: |
2563 | + cur_exec_path = os.path.abspath(sys.executable) |
2564 | + exe_dir = os.path.dirname(cur_exec_path) |
2565 | + return os.path.join(exe_dir, exe_name + ".exe") |
2566 | + |
2567 | + |
2568 | +def _get_exe_path_frozen_darwin(exe_name, app_names): |
2569 | + """Get path to the sub-app executable on packaged darwin.""" |
2570 | + |
2571 | + sub_app_name = app_names[exe_name] |
2572 | + main_app_dir = "".join(__file__.partition(".app")[:-1]) |
2573 | + main_app_resources_dir = os.path.join(main_app_dir, |
2574 | + "Contents", |
2575 | + "Resources") |
2576 | + exe_bin = os.path.join(main_app_resources_dir, |
2577 | + sub_app_name, |
2578 | + "Contents", "MacOS", |
2579 | + exe_name) |
2580 | + return exe_bin |
2581 | + |
2582 | + |
2583 | +def get_program_path(program_name, *args, **kwargs): |
2584 | + """Given a program name, returns the path to run that program. |
2585 | + |
2586 | + Raises OSError if the program is not found. |
2587 | + |
2588 | + :param program_name: The name of the program to find. For darwin and win32 |
2589 | + platforms, the behavior is changed slightly, when sys.frozen is set, |
2590 | + to look in the packaged program locations for the program. |
2591 | + :param search_dirs: A list of directories to look for the program in. This |
2592 | + is only available as a keyword argument. |
2593 | + :param app_names: A dict of program names mapped to sub-app names. Used |
2594 | + for discovering paths in embedded .app bundles on the darwin platform. |
2595 | + This is only available as a keyword argument. |
2596 | + :return: The path to the discovered program. |
2597 | + """ |
2598 | + search_dirs = kwargs.get('fallback_dirs', None) |
2599 | + app_names = kwargs.get('app_names', None) |
2600 | + |
2601 | + if getattr(sys, "frozen", None) is not None: |
2602 | + if sys.platform == 'win32': |
2603 | + program_path = _get_exe_path_frozen_win32(program_name) |
2604 | + elif sys.platform == 'darwin': |
2605 | + program_path = _get_exe_path_frozen_darwin(program_name, |
2606 | + app_names) |
2607 | + else: |
2608 | + raise Exception("Unsupported platform for frozen execution: %r" % |
2609 | + sys.platform) |
2610 | + else: |
2611 | + if search_dirs is not None: |
2612 | + for dirname in search_dirs: |
2613 | + program_path = os.path.join(dirname, program_name) |
2614 | + if os.path.exists(program_path): |
2615 | + return program_path |
2616 | + else: |
2617 | + # Check in normal system $PATH, if no fallback dirs specified |
2618 | + from distutils.spawn import find_executable |
2619 | + program_path = find_executable(program_name) |
2620 | + |
2621 | + if program_path is None or not os.path.exists(program_path): |
2622 | + raise OSError(errno.ENOENT, |
2623 | + "Could not find executable %r" % program_name) |
2624 | + |
2625 | + return program_path |
2626 | + |
2627 | + |
2628 | +def get_env_path(key, default): |
2629 | + """Get a UTF-8 encoded path from an environment variable.""" |
2630 | + if key in os.environ: |
2631 | + # on windows, environment variables are mbcs bytes |
2632 | + # so we must turn them into utf-8 Syncdaemon paths |
2633 | + try: |
2634 | + path = os.environb.get(key.encode('utf-8')) |
2635 | + except AttributeError: |
2636 | + path = os.environ[key] |
2637 | + return path.decode(sys.getfilesystemencoding()).encode('utf-8') |
2638 | + else: |
2639 | + if not isinstance(default, bytes): |
2640 | + return default.encode('utf-8') |
2641 | + return default |
2642 | + |
2643 | + |
2644 | +def unicode_path(utf8path): |
2645 | + """Turn an utf8 path into a unicode path.""" |
2646 | + if isinstance(utf8path, bytes): |
2647 | + return utf8path.decode("utf-8") |
2648 | + return utf8path |
2649 | + |
2650 | + |
2651 | +def get_special_folders(): |
2652 | + """ Routine to grab all the Windows Special Folders locations. |
2653 | + |
2654 | + If successful, returns dictionary |
2655 | + of shell folder locations indexed on Windows keyword for each; |
2656 | + otherwise, returns an empty dictionary. |
2657 | + """ |
2658 | + # pylint: disable=W0621, F0401, E0611 |
2659 | + special_folders = {} |
2660 | + |
2661 | + if sys.platform == 'win32': |
2662 | + from win32com.shell import shell, shellcon |
2663 | + # CSIDL_LOCAL_APPDATA = C:\Users\<username>\AppData\Local |
2664 | + # CSIDL_PROFILE = C:\Users\<username> |
2665 | + # CSIDL_COMMON_APPDATA = C:\ProgramData |
2666 | + # More information on these constants at |
2667 | + # http://msdn.microsoft.com/en-us/library/bb762494 |
2668 | + |
2669 | + # per http://msdn.microsoft.com/en-us/library/windows/desktop/bb762181, |
2670 | + # SHGetFolderPath is deprecated, replaced by SHGetKnownFolderPath |
2671 | + # (http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188) |
2672 | + def get_path(name): |
2673 | + return shell.SHGetFolderPath(0, getattr(shellcon, name), |
2674 | + None, 0).encode('utf8') |
2675 | + special_folders['Personal'] = get_path("CSIDL_PROFILE") |
2676 | + special_folders['Local AppData'] = get_path("CSIDL_LOCAL_APPDATA") |
2677 | + special_folders['AppData'] = os.path.dirname( |
2678 | + special_folders['Local AppData']) |
2679 | + special_folders['Common AppData'] = get_path("CSIDL_COMMON_APPDATA") |
2680 | + |
2681 | + return special_folders |
2682 | + |
2683 | + |
2684 | +# pylint: disable=C0103 |
2685 | +if sys.platform == 'win32': |
2686 | + special_folders = get_special_folders() |
2687 | + user_home = special_folders['Personal'] |
2688 | + default_config_path = special_folders['Common AppData'] |
2689 | + default_config_home = special_folders['Local AppData'] |
2690 | + default_data_path = os.path.join(default_config_path, b'xdg') |
2691 | + default_data_home = os.path.join(default_config_home, b'xdg') |
2692 | + default_cache_home = os.path.join(default_data_home, b'cache') |
2693 | +elif sys.platform == 'darwin': |
2694 | + user_home = os.path.expanduser(b'~') |
2695 | + default_cache_home = os.path.join(user_home, b'Library', b'Caches') |
2696 | + default_config_path = b'/Library/Preferences:/etc/xdg' |
2697 | + default_config_home = os.path.join(user_home, b'Library', b'Preferences') |
2698 | + default_data_path = b':'.join([b'/Library/Application Support', |
2699 | + b'/usr/local/share', |
2700 | + b'/usr/share']) |
2701 | + default_data_home = os.path.join(user_home, b'Library', |
2702 | + b'Application Support') |
2703 | +else: |
2704 | + user_home = os.path.expanduser(b'~') |
2705 | + default_cache_home = os.path.join(user_home, |
2706 | + b'.cache') |
2707 | + default_config_path = b'/etc/xdg' |
2708 | + default_config_home = os.path.join(user_home, |
2709 | + b'.config') |
2710 | + default_data_path = b'/usr/local/share:/usr/share' |
2711 | + default_data_home = os.path.join(user_home, |
2712 | + b'.local', b'share') |
2713 | |
2714 | === added file 'contrib/u1trial' |
2715 | --- contrib/u1trial 1970-01-01 00:00:00 +0000 |
2716 | +++ contrib/u1trial 2018-06-03 23:09:20 +0000 |
2717 | @@ -0,0 +1,41 @@ |
2718 | +#! /usr/bin/python |
2719 | +# |
2720 | +# Copyright 2009-2012 Canonical Ltd. |
2721 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
2722 | +# |
2723 | +# This program is free software: you can redistribute it and/or modify it |
2724 | +# under the terms of the GNU General Public License version 3, as published |
2725 | +# by the Free Software Foundation. |
2726 | +# |
2727 | +# This program is distributed in the hope that it will be useful, but |
2728 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
2729 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2730 | +# PURPOSE. See the GNU General Public License for more details. |
2731 | +# |
2732 | +# You should have received a copy of the GNU General Public License along |
2733 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
2734 | +# |
2735 | +# In addition, as a special exception, the copyright holders give |
2736 | +# permission to link the code of portions of this program with the |
2737 | +# OpenSSL library under certain conditions as described in each |
2738 | +# individual source file, and distribute linked combinations |
2739 | +# including the two. |
2740 | +# You must obey the GNU General Public License in all respects |
2741 | +# for all of the code used other than OpenSSL. If you modify |
2742 | +# file(s) with this exception, you may extend this exception to your |
2743 | +# version of the file(s), but you are not obligated to do so. If you |
2744 | +# do not wish to do so, delete this exception statement from your |
2745 | +# version. If you delete this exception statement from all source |
2746 | +# files in the program, then also delete it here. |
2747 | +"""Test runner which works with special services and main loops.""" |
2748 | + |
2749 | +import os |
2750 | +import sys |
2751 | + |
2752 | +sys.path.insert(0, os.path.abspath(".")) |
2753 | + |
2754 | +from devtools.runners import main |
2755 | + |
2756 | + |
2757 | +if __name__ == '__main__': |
2758 | + main() |
2759 | |
2760 | === modified file 'dependencies-devel.txt' |
2761 | --- dependencies-devel.txt 2018-03-18 11:59:08 +0000 |
2762 | +++ dependencies-devel.txt 2018-06-03 23:09:20 +0000 |
2763 | @@ -1,5 +1,2 @@ |
2764 | bzr |
2765 | make |
2766 | -python-mocker |
2767 | -ubuntuone-dev-tools |
2768 | -virtualenv |
2769 | |
2770 | === modified file 'dependencies.txt' |
2771 | --- dependencies.txt 2018-04-14 23:34:20 +0000 |
2772 | +++ dependencies.txt 2018-06-03 23:09:20 +0000 |
2773 | @@ -1,8 +1,5 @@ |
2774 | -gir1.2-soup-2.4 |
2775 | -python-configglue |
2776 | -python-dirspec |
2777 | -python-distutils-extra |
2778 | -python-gi |
2779 | -python-protobuf |
2780 | -python-pyinotify |
2781 | -python-twisted |
2782 | +libgirepository1.0-dev |
2783 | +libgtk2.0-dev |
2784 | +pkg-config |
2785 | +python-dev |
2786 | +virtualenv |
2787 | |
2788 | === modified file 'magicicadaclient/platform/tests/filesystem_notifications/__init__.py' |
2789 | --- magicicadaclient/platform/tests/filesystem_notifications/__init__.py 2018-05-19 20:44:54 +0000 |
2790 | +++ magicicadaclient/platform/tests/filesystem_notifications/__init__.py 2018-06-03 23:09:20 +0000 |
2791 | @@ -1,4 +1,5 @@ |
2792 | # Copyright 2012 Canonical Ltd. |
2793 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
2794 | # |
2795 | # This program is free software: you can redistribute it and/or modify it |
2796 | # under the terms of the GNU General Public License version 3, as published |
2797 | @@ -30,10 +31,10 @@ |
2798 | |
2799 | from twisted.internet import defer, reactor |
2800 | |
2801 | -from magicicadaclient.testing import testcase |
2802 | -from ubuntuone.devtools.handlers import MementoHandler |
2803 | +from devtools.handlers import MementoHandler |
2804 | from magicicadaclient.syncdaemon import event_queue, filesystem_manager |
2805 | from magicicadaclient.syncdaemon.tritcask import Tritcask |
2806 | +from magicicadaclient.testing import testcase |
2807 | |
2808 | |
2809 | class BaseFSMonitorTestCase(testcase.BaseTwistedTestCase): |
2810 | |
2811 | === modified file 'magicicadaclient/platform/tests/filesystem_notifications/common.py' |
2812 | --- magicicadaclient/platform/tests/filesystem_notifications/common.py 2018-05-19 20:44:54 +0000 |
2813 | +++ magicicadaclient/platform/tests/filesystem_notifications/common.py 2018-06-03 23:09:20 +0000 |
2814 | @@ -1,8 +1,5 @@ |
2815 | -# |
2816 | -# Authors: Manuel de la Pena <manuel@canonical.com> |
2817 | -# Alejandro J. Cura <alecu@canonical.com> |
2818 | -# |
2819 | # Copyright 2011-2012 Canonical Ltd. |
2820 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
2821 | # |
2822 | # This program is free software: you can redistribute it and/or modify it |
2823 | # under the terms of the GNU General Public License version 3, as published |
2824 | @@ -38,16 +35,18 @@ |
2825 | import itertools |
2826 | |
2827 | from twisted.internet import defer |
2828 | + |
2829 | +from devtools.handlers import MementoHandler |
2830 | from magicicadaclient.testing.testcase import BaseTwistedTestCase |
2831 | -from ubuntuone.devtools.handlers import MementoHandler |
2832 | -from magicicadaclient.platform.filesystem_notifications.pyinotify_agnostic import ( |
2833 | - EventsCodes, |
2834 | - ProcessEvent, |
2835 | - IN_CLOSE_WRITE, |
2836 | - IN_CREATE, |
2837 | - IN_DELETE, |
2838 | - IN_OPEN, |
2839 | -) |
2840 | +from magicicadaclient.platform.filesystem_notifications.pyinotify_agnostic \ |
2841 | + import ( |
2842 | + EventsCodes, |
2843 | + ProcessEvent, |
2844 | + IN_CLOSE_WRITE, |
2845 | + IN_CREATE, |
2846 | + IN_DELETE, |
2847 | + IN_OPEN, |
2848 | + ) |
2849 | from magicicadaclient.platform.filesystem_notifications import notify_processor |
2850 | from magicicadaclient.platform.filesystem_notifications.monitor.common import ( |
2851 | FilesystemMonitor, |
2852 | |
2853 | === modified file 'magicicadaclient/platform/tests/filesystem_notifications/test_darwin.py' |
2854 | --- magicicadaclient/platform/tests/filesystem_notifications/test_darwin.py 2018-05-19 20:44:54 +0000 |
2855 | +++ magicicadaclient/platform/tests/filesystem_notifications/test_darwin.py 2018-06-03 23:09:20 +0000 |
2856 | @@ -1,6 +1,7 @@ |
2857 | # -*- coding: utf-8 *-* |
2858 | # |
2859 | # Copyright 2012 Canonical Ltd. |
2860 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
2861 | # |
2862 | # This program is free software: you can redistribute it and/or modify it |
2863 | # under the terms of the GNU General Public License version 3, as published |
2864 | @@ -38,9 +39,8 @@ |
2865 | |
2866 | import fsevents |
2867 | |
2868 | +from devtools.handlers import MementoHandler |
2869 | from magicicadaclient.testing.testcase import BaseTwistedTestCase |
2870 | - |
2871 | -from ubuntuone.devtools.handlers import MementoHandler |
2872 | from magicicadaclient.platform.filesystem_notifications.monitor import ( |
2873 | common, |
2874 | ) |
2875 | @@ -52,13 +52,14 @@ |
2876 | Watch, |
2877 | WatchManager, |
2878 | ) |
2879 | -from magicicadaclient.platform.filesystem_notifications.pyinotify_agnostic import ( |
2880 | - ProcessEvent, |
2881 | - IN_CLOSE_WRITE, |
2882 | - IN_CREATE, |
2883 | - IN_DELETE, |
2884 | - IN_OPEN, |
2885 | -) |
2886 | +from magicicadaclient.platform.filesystem_notifications.pyinotify_agnostic \ |
2887 | + import ( |
2888 | + ProcessEvent, |
2889 | + IN_CLOSE_WRITE, |
2890 | + IN_CREATE, |
2891 | + IN_DELETE, |
2892 | + IN_OPEN, |
2893 | + ) |
2894 | from magicicadaclient.platform.tests.filesystem_notifications import ( |
2895 | BaseFSMonitorTestCase, |
2896 | common as common_tests, |
2897 | |
2898 | === modified file 'magicicadaclient/platform/tests/filesystem_notifications/test_filesystem_notifications.py' |
2899 | --- magicicadaclient/platform/tests/filesystem_notifications/test_filesystem_notifications.py 2018-05-19 20:44:54 +0000 |
2900 | +++ magicicadaclient/platform/tests/filesystem_notifications/test_filesystem_notifications.py 2018-06-03 23:09:20 +0000 |
2901 | @@ -1,6 +1,7 @@ |
2902 | # -*- coding: utf-8 -*- |
2903 | # |
2904 | # Copyright 2009-2012 Canonical Ltd. |
2905 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
2906 | # |
2907 | # This program is free software: you can redistribute it and/or modify it |
2908 | # under the terms of the GNU General Public License version 3, as published |
2909 | @@ -33,8 +34,8 @@ |
2910 | |
2911 | from twisted.internet import defer, reactor |
2912 | from twisted.trial import unittest |
2913 | -from ubuntuone.devtools.handlers import MementoHandler |
2914 | |
2915 | +from devtools.handlers import MementoHandler |
2916 | from magicicadaclient.testing.testcase import ( |
2917 | BaseTwistedTestCase, |
2918 | FakeVolumeManager, |
2919 | |
2920 | === modified file 'magicicadaclient/platform/tests/filesystem_notifications/test_fsevents_daemon.py' |
2921 | --- magicicadaclient/platform/tests/filesystem_notifications/test_fsevents_daemon.py 2018-05-19 20:44:54 +0000 |
2922 | +++ magicicadaclient/platform/tests/filesystem_notifications/test_fsevents_daemon.py 2018-06-03 23:09:20 +0000 |
2923 | @@ -1,6 +1,7 @@ |
2924 | # -*- coding: utf-8 *-* |
2925 | # |
2926 | # Copyright 2012 Canonical Ltd. |
2927 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
2928 | # |
2929 | # This program is free software: you can redistribute it and/or modify it |
2930 | # under the terms of the GNU General Public License version 3, as published |
2931 | @@ -32,24 +33,20 @@ |
2932 | |
2933 | from twisted.internet import defer, protocol |
2934 | |
2935 | +from devtools.testcases.txsocketserver import TidyUnixServer |
2936 | from magicicadaclient.testing.testcase import BaseTwistedTestCase |
2937 | from magicicadaclient import fseventsd |
2938 | -try: |
2939 | - from ubuntuone.devtools.testcases import skipIf |
2940 | - from ubuntuone.devtools.testcases.txsocketserver import TidyUnixServer |
2941 | -except ImportError: |
2942 | - from ubuntuone.devtools.testcase import skipIf |
2943 | - TidyUnixServer = None |
2944 | from magicicadaclient.platform.filesystem_notifications.monitor.darwin import ( |
2945 | fsevents_daemon, |
2946 | ) |
2947 | -from magicicadaclient.platform.filesystem_notifications.pyinotify_agnostic import ( |
2948 | - IN_CREATE, |
2949 | - IN_DELETE, |
2950 | - IN_MODIFY, |
2951 | - IN_MOVED_FROM, |
2952 | - IN_MOVED_TO, |
2953 | -) |
2954 | +from magicicadaclient.platform.filesystem_notifications.pyinotify_agnostic \ |
2955 | + import ( |
2956 | + IN_CREATE, |
2957 | + IN_DELETE, |
2958 | + IN_MODIFY, |
2959 | + IN_MOVED_FROM, |
2960 | + IN_MOVED_TO, |
2961 | + ) |
2962 | |
2963 | |
2964 | class FakeServerProtocol(protocol.Protocol): |
2965 | @@ -469,8 +466,6 @@ |
2966 | yield self.monitor.add_watch(dirpath) |
2967 | self.assertNotIn('add_path', self.protocol.called) |
2968 | |
2969 | - @skipIf(TidyUnixServer is None, |
2970 | - 'Testcases from txsocketserver not availble.') |
2971 | @defer.inlineCallbacks |
2972 | def test_is_available_monitor_running(self): |
2973 | """Test the method when it is indeed running.""" |
2974 | |
2975 | === modified file 'magicicadaclient/platform/tests/ipc/test_linux.py' |
2976 | --- magicicadaclient/platform/tests/ipc/test_linux.py 2018-05-19 20:44:54 +0000 |
2977 | +++ magicicadaclient/platform/tests/ipc/test_linux.py 2018-06-03 23:09:20 +0000 |
2978 | @@ -1,6 +1,7 @@ |
2979 | # -*- coding: utf-8 -*- |
2980 | # |
2981 | # Copyright 2009-2012 Canonical Ltd. |
2982 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
2983 | # |
2984 | # This program is free software: you can redistribute it and/or modify it |
2985 | # under the terms of the GNU General Public License version 3, as published |
2986 | @@ -33,11 +34,8 @@ |
2987 | import dbus |
2988 | |
2989 | from twisted.internet import defer |
2990 | -try: |
2991 | - from ubuntuone.devtools.testcases.dbus import DBusTestCase |
2992 | -except ImportError: |
2993 | - from ubuntuone.devtools.testcase import DBusTestCase |
2994 | |
2995 | +from devtools.testcases.dbus import DBusTestCase |
2996 | from magicicadaclient.testing.testcase import ( |
2997 | FakeMainTestCase, |
2998 | FakedService, |
2999 | |
3000 | === modified file 'magicicadaclient/platform/tests/ipc/test_perspective_broker.py' |
3001 | --- magicicadaclient/platform/tests/ipc/test_perspective_broker.py 2018-05-19 20:44:54 +0000 |
3002 | +++ magicicadaclient/platform/tests/ipc/test_perspective_broker.py 2018-06-03 23:09:20 +0000 |
3003 | @@ -1,6 +1,7 @@ |
3004 | # -*- coding: utf-8 -*- |
3005 | # |
3006 | # Copyright 2011-2012 Canonical Ltd. |
3007 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
3008 | # |
3009 | # This program is free software: you can redistribute it and/or modify it |
3010 | # under the terms of the GNU General Public License version 3, as published |
3011 | @@ -41,14 +42,8 @@ |
3012 | ) |
3013 | from twisted.trial.unittest import TestCase |
3014 | |
3015 | -from magicicadaclient.testing.testcase import ( |
3016 | - FakedService, |
3017 | - FakeMainTestCase, |
3018 | -) |
3019 | -try: |
3020 | - from ubuntuone.devtools.testcases import skipIf, skipIfOS |
3021 | -except ImportError: |
3022 | - from ubuntuone.devtools.testcase import skipIf, skipIfOS |
3023 | +from devtools.testcases import skipIf, skipIfOS |
3024 | +from magicicadaclient.testing.testcase import FakedService, FakeMainTestCase |
3025 | from magicicadaclient.platform.ipc import perspective_broker as ipc |
3026 | from magicicadaclient.platform.ipc.perspective_broker import ( |
3027 | Config, |
3028 | |
3029 | === modified file 'magicicadaclient/platform/tests/os_helper/test_darwin.py' |
3030 | --- magicicadaclient/platform/tests/os_helper/test_darwin.py 2018-05-19 20:44:54 +0000 |
3031 | +++ magicicadaclient/platform/tests/os_helper/test_darwin.py 2018-06-03 23:09:20 +0000 |
3032 | @@ -1,7 +1,7 @@ |
3033 | # -*- encoding: utf-8 -*- |
3034 | -# tests.platform.os_helper - darwin platform tests |
3035 | # |
3036 | # Copyright 2012 Canonical Ltd. |
3037 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
3038 | # |
3039 | # This program is free software: you can redistribute it and/or modify it |
3040 | # under the terms of the GNU General Public License version 3, as published |
3041 | @@ -33,13 +33,9 @@ |
3042 | import os |
3043 | |
3044 | from twisted.internet import defer |
3045 | -from ubuntuone.devtools.handlers import MementoHandler |
3046 | |
3047 | -from magicicadaclient.platform import ( |
3048 | - move_to_trash, |
3049 | - open_file, |
3050 | - stat_path, |
3051 | -) |
3052 | +from devtools.handlers import MementoHandler |
3053 | +from magicicadaclient.platform import move_to_trash, open_file, stat_path |
3054 | from magicicadaclient.platform.os_helper import darwin |
3055 | from magicicadaclient.platform.tests.os_helper import test_os_helper |
3056 | |
3057 | |
3058 | === modified file 'magicicadaclient/platform/tests/os_helper/test_linux.py' |
3059 | --- magicicadaclient/platform/tests/os_helper/test_linux.py 2018-05-19 20:44:54 +0000 |
3060 | +++ magicicadaclient/platform/tests/os_helper/test_linux.py 2018-06-03 23:09:20 +0000 |
3061 | @@ -1,4 +1,5 @@ |
3062 | # Copyright 2010-2013 Canonical Ltd. |
3063 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
3064 | # |
3065 | # This program is free software: you can redistribute it and/or modify it |
3066 | # under the terms of the GNU General Public License version 3, as published |
3067 | @@ -30,15 +31,11 @@ |
3068 | import os |
3069 | |
3070 | from twisted.internet import defer |
3071 | -from ubuntuone.devtools.handlers import MementoHandler |
3072 | |
3073 | +from devtools.handlers import MementoHandler |
3074 | +from magicicadaclient.platform import move_to_trash, open_file, stat_path |
3075 | from magicicadaclient.platform.tests.os_helper import test_os_helper |
3076 | from magicicadaclient.platform.os_helper import linux |
3077 | -from magicicadaclient.platform import ( |
3078 | - move_to_trash, |
3079 | - open_file, |
3080 | - stat_path, |
3081 | -) |
3082 | |
3083 | |
3084 | class OSWrapperTests(test_os_helper.OSWrapperTests): |
3085 | |
3086 | === modified file 'magicicadaclient/platform/tests/session/test_common.py' |
3087 | --- magicicadaclient/platform/tests/session/test_common.py 2018-05-19 20:44:54 +0000 |
3088 | +++ magicicadaclient/platform/tests/session/test_common.py 2018-06-03 23:09:20 +0000 |
3089 | @@ -1,5 +1,6 @@ |
3090 | # |
3091 | # Copyright 2011-2012 Canonical Ltd. |
3092 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
3093 | # |
3094 | # This program is free software: you can redistribute it and/or modify it |
3095 | # under the terms of the GNU General Public License version 3, as published |
3096 | @@ -30,7 +31,7 @@ |
3097 | from twisted.internet import defer |
3098 | from twisted.trial.unittest import TestCase |
3099 | |
3100 | -from ubuntuone.devtools.testcases import skipIfOS |
3101 | +from devtools.testcases import skipIfOS |
3102 | from magicicadaclient.platform.session import Inhibitor, INHIBIT_LOGOUT_SUSPEND |
3103 | |
3104 | |
3105 | |
3106 | === modified file 'magicicadaclient/platform/tests/session/test_linux.py' |
3107 | --- magicicadaclient/platform/tests/session/test_linux.py 2018-05-19 20:44:54 +0000 |
3108 | +++ magicicadaclient/platform/tests/session/test_linux.py 2018-06-03 23:09:20 +0000 |
3109 | @@ -1,8 +1,5 @@ |
3110 | -# tests.platform.linux.test_session |
3111 | -# |
3112 | -# Author: Alejandro J. Cura <alecu@canonical.com> |
3113 | -# |
3114 | # Copyright 2011-2012 Canonical Ltd. |
3115 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
3116 | # |
3117 | # This program is free software: you can redistribute it and/or modify it |
3118 | # under the terms of the GNU General Public License version 3, as published |
3119 | @@ -30,15 +27,13 @@ |
3120 | # files in the program, then also delete it here. |
3121 | """Tests for the session inhibition DBus client.""" |
3122 | |
3123 | +import operator |
3124 | + |
3125 | import dbus |
3126 | -import operator |
3127 | - |
3128 | from dbus.mainloop.glib import DBusGMainLoop |
3129 | from twisted.internet.defer import inlineCallbacks |
3130 | -try: |
3131 | - from ubuntuone.devtools.testcases.dbus import DBusTestCase |
3132 | -except ImportError: |
3133 | - from ubuntuone.devtools.testcase import DBusTestCase |
3134 | + |
3135 | +from devtools.testcases.dbus import DBusTestCase |
3136 | from magicicadaclient.platform import session |
3137 | |
3138 | INHIBIT_ALL = (session.INHIBIT_LOGGING_OUT | |
3139 | @@ -137,9 +132,8 @@ |
3140 | def test_uninhibit_call(self): |
3141 | """Test the uninhibit call.""" |
3142 | fakeinhibitor = self.register_fakeserver( |
3143 | - session.SESSION_MANAGER_BUSNAME, |
3144 | - session.SESSION_MANAGER_PATH, |
3145 | - FakeGnomeSessionManagerInhibitor) |
3146 | + session.SESSION_MANAGER_BUSNAME, session.SESSION_MANAGER_PATH, |
3147 | + FakeGnomeSessionManagerInhibitor) |
3148 | i = yield session.inhibit_logout_suspend("fake reason") |
3149 | yield i.cancel() |
3150 | result = fakeinhibitor.IsInhibited(session.INHIBIT_LOGGING_OUT) |
3151 | |
3152 | === modified file 'magicicadaclient/platform/tests/test_tools.py' |
3153 | --- magicicadaclient/platform/tests/test_tools.py 2018-05-19 20:44:54 +0000 |
3154 | +++ magicicadaclient/platform/tests/test_tools.py 2018-06-03 23:09:20 +0000 |
3155 | @@ -30,15 +30,15 @@ |
3156 | """Tests for the syncdaemon tools module.""" |
3157 | |
3158 | import os |
3159 | - |
3160 | from collections import defaultdict |
3161 | |
3162 | from twisted.internet import defer, reactor |
3163 | -from ubuntuone.devtools.handlers import MementoHandler |
3164 | -from ubuntuone.devtools.testcases import skipTest, skipIfNotOS |
3165 | |
3166 | +from devtools.handlers import MementoHandler |
3167 | +from devtools.testcases import skipTest, skipIfNotOS |
3168 | from magicicadaclient.testing.testcase import FakeCommand |
3169 | - |
3170 | +from magicicadaclient.platform import tools |
3171 | +from magicicadaclient.platform.tests import IPCTestCase |
3172 | from magicicadaclient.syncdaemon import ( |
3173 | action_queue, |
3174 | event_queue, |
3175 | @@ -46,8 +46,6 @@ |
3176 | states, |
3177 | volume_manager, |
3178 | ) |
3179 | -from magicicadaclient.platform import tools |
3180 | -from magicicadaclient.platform.tests import IPCTestCase |
3181 | |
3182 | |
3183 | SOME_ERROR = 'CRASH BOOM BANG' |
3184 | |
3185 | === modified file 'magicicadaclient/syncdaemon/tests/test_action_queue.py' |
3186 | --- magicicadaclient/syncdaemon/tests/test_action_queue.py 2018-05-19 20:44:54 +0000 |
3187 | +++ magicicadaclient/syncdaemon/tests/test_action_queue.py 2018-06-03 23:09:20 +0000 |
3188 | @@ -60,16 +60,8 @@ |
3189 | from twisted.trial.unittest import TestCase as TwistedTestCase |
3190 | from zope.interface.verify import verifyObject, verifyClass |
3191 | |
3192 | -from magicicadaclient.testing.testcase import ( |
3193 | - BaseTwistedTestCase, |
3194 | - DummyClass, |
3195 | - FakeActionQueue, |
3196 | - FakeCommand, |
3197 | - FakeMain, |
3198 | - FakeUpload, |
3199 | -) |
3200 | -from ubuntuone.devtools import handlers |
3201 | -from ubuntuone.devtools.testcases import skipTest |
3202 | +from devtools import handlers |
3203 | +from devtools.testcases import skipTest |
3204 | from magicicadaclient import logger, clientdefs |
3205 | from magicicadaclient.platform import open_file, platform, path_exists |
3206 | from magicicadaclient.syncdaemon import interfaces, config |
3207 | @@ -88,6 +80,14 @@ |
3208 | from magicicadaclient.syncdaemon import offload_queue |
3209 | from magicicadaclient.syncdaemon.marker import MDMarker |
3210 | from magicicadaclient.syncdaemon.volume_manager import ACCESS_LEVEL_RO |
3211 | +from magicicadaclient.testing.testcase import ( |
3212 | + BaseTwistedTestCase, |
3213 | + DummyClass, |
3214 | + FakeActionQueue, |
3215 | + FakeCommand, |
3216 | + FakeMain, |
3217 | + FakeUpload, |
3218 | +) |
3219 | |
3220 | PATH = os.path.join(u'~', u'Documents', u'pdfs', u'moño', u'') |
3221 | NAME = u'UDF-me' |
3222 | @@ -3352,7 +3352,7 @@ |
3223 | |
3224 | def test_progress_hook(self): |
3225 | """Test the progress hook.""" |
3226 | - self.command.deflated_size = 2*TRANSFER_PROGRESS_THRESHOLD |
3227 | + self.command.deflated_size = 2 * TRANSFER_PROGRESS_THRESHOLD |
3228 | self.command.n_bytes_written_last = 0 |
3229 | |
3230 | self.command.n_bytes_written = 5 |
3231 | @@ -3368,8 +3368,8 @@ |
3232 | self.command.n_bytes_written = TRANSFER_PROGRESS_THRESHOLD + 5 |
3233 | self.command.progress_hook() |
3234 | kwargs = {'share_id': self.command.share_id, 'node_id': 'a_node_id', |
3235 | - 'deflated_size': 2*TRANSFER_PROGRESS_THRESHOLD, |
3236 | - 'n_bytes_written': 5+TRANSFER_PROGRESS_THRESHOLD} |
3237 | + 'deflated_size': 2 * TRANSFER_PROGRESS_THRESHOLD, |
3238 | + 'n_bytes_written': 5 + TRANSFER_PROGRESS_THRESHOLD} |
3239 | events = [('AQ_UPLOAD_FILE_PROGRESS', kwargs)] |
3240 | self.assertEqual(events, self.command.action_queue.event_queue.events) |
3241 | self.assertEqual(self.command.n_bytes_written_last, |
3242 | @@ -4932,7 +4932,7 @@ |
3243 | |
3244 | def test_repr(self): |
3245 | """A DeltaList has a short representation.""" |
3246 | - a = DeltaList(["a"*1000]) |
3247 | + a = DeltaList(["a" * 1000]) |
3248 | self.assertTrue(len(repr(a)) < 100) |
3249 | self.assertTrue(len(str(a)) < 100) |
3250 | |
3251 | |
3252 | === modified file 'magicicadaclient/syncdaemon/tests/test_eq_inotify.py' |
3253 | --- magicicadaclient/syncdaemon/tests/test_eq_inotify.py 2018-05-19 20:44:54 +0000 |
3254 | +++ magicicadaclient/syncdaemon/tests/test_eq_inotify.py 2018-06-03 23:09:20 +0000 |
3255 | @@ -1,9 +1,5 @@ |
3256 | -# tests.syncdaemon.test_eq_inotify |
3257 | -# |
3258 | -# Authors: Facundo Batista <facundo@canonical.com> |
3259 | -# Manuel de la Pena <manuel@canonical.com> |
3260 | -# |
3261 | # Copyright 2009-2012 Canonical Ltd. |
3262 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
3263 | # |
3264 | # This program is free software: you can redistribute it and/or modify it |
3265 | # under the terms of the GNU General Public License version 3, as published |
3266 | @@ -37,17 +33,9 @@ |
3267 | import sys |
3268 | |
3269 | from twisted.internet import defer, reactor |
3270 | -from ubuntuone.devtools.handlers import MementoHandler |
3271 | -from ubuntuone.devtools.testcases import skipIfOS, skipIfNotOS |
3272 | |
3273 | -from magicicadaclient.testing.testcase import ( |
3274 | - BaseTwistedTestCase, |
3275 | - FakeMain, |
3276 | - Listener, |
3277 | - skip_if_darwin_missing_fs_event, |
3278 | - skip_if_win32_missing_fs_event, |
3279 | -) |
3280 | -from magicicadaclient.syncdaemon.tests.test_eventqueue import BaseEQTestCase |
3281 | +from devtools.handlers import MementoHandler |
3282 | +from devtools.testcases import skipIfOS, skipIfNotOS |
3283 | from magicicadaclient.platform import ( |
3284 | make_link, |
3285 | make_dir, |
3286 | @@ -61,6 +49,14 @@ |
3287 | set_dir_readwrite, |
3288 | ) |
3289 | from magicicadaclient.syncdaemon import event_queue, volume_manager |
3290 | +from magicicadaclient.syncdaemon.tests.test_eventqueue import BaseEQTestCase |
3291 | +from magicicadaclient.testing.testcase import ( |
3292 | + BaseTwistedTestCase, |
3293 | + FakeMain, |
3294 | + Listener, |
3295 | + skip_if_darwin_missing_fs_event, |
3296 | + skip_if_win32_missing_fs_event, |
3297 | +) |
3298 | |
3299 | # our logging level |
3300 | TRACE = logging.getLevelName('TRACE') |
3301 | |
3302 | === modified file 'magicicadaclient/syncdaemon/tests/test_eventqueue.py' |
3303 | --- magicicadaclient/syncdaemon/tests/test_eventqueue.py 2018-05-19 20:44:54 +0000 |
3304 | +++ magicicadaclient/syncdaemon/tests/test_eventqueue.py 2018-06-03 23:09:20 +0000 |
3305 | @@ -1,9 +1,5 @@ |
3306 | -# |
3307 | -# Author: Facundo Batista <facundo@canonical.com> |
3308 | -# |
3309 | -# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> |
3310 | -# |
3311 | # Copyright 2009-2012 Canonical Ltd. |
3312 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
3313 | # |
3314 | # This program is free software: you can redistribute it and/or modify it |
3315 | # under the terms of the GNU General Public License version 3, as published |
3316 | @@ -36,6 +32,7 @@ |
3317 | from twisted.internet import defer |
3318 | from twisted.trial.unittest import TestCase |
3319 | |
3320 | +from devtools.handlers import MementoHandler |
3321 | from magicicadaclient.testing.testcase import ( |
3322 | BaseTwistedTestCase, |
3323 | FakeMonitor, |
3324 | @@ -49,7 +46,6 @@ |
3325 | filesystem_manager, |
3326 | tritcask, |
3327 | ) |
3328 | -from ubuntuone.devtools.handlers import MementoHandler |
3329 | |
3330 | |
3331 | class BaseEQTestCase(BaseTwistedTestCase): |
3332 | |
3333 | === modified file 'magicicadaclient/syncdaemon/tests/test_fileshelf.py' |
3334 | --- magicicadaclient/syncdaemon/tests/test_fileshelf.py 2018-05-19 20:44:54 +0000 |
3335 | +++ magicicadaclient/syncdaemon/tests/test_fileshelf.py 2018-06-03 23:09:20 +0000 |
3336 | @@ -1,7 +1,5 @@ |
3337 | -# |
3338 | -# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> |
3339 | -# |
3340 | # Copyright 2009-2012 Canonical Ltd. |
3341 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
3342 | # |
3343 | # This program is free software: you can redistribute it and/or modify it |
3344 | # under the terms of the GNU General Public License version 3, as published |
3345 | @@ -37,19 +35,16 @@ |
3346 | import unittest |
3347 | |
3348 | from twisted.internet import defer |
3349 | -from ubuntuone.devtools.testcases import skipIfOS |
3350 | |
3351 | -from magicicadaclient.testing.testcase import BaseTwistedTestCase |
3352 | -from magicicadaclient.platform import ( |
3353 | - open_file, |
3354 | - path_exists, |
3355 | -) |
3356 | +from devtools.testcases import skipIfOS |
3357 | +from magicicadaclient.platform import open_file, path_exists |
3358 | from magicicadaclient.syncdaemon.file_shelf import ( |
3359 | FileShelf, |
3360 | CachedFileShelf, |
3361 | LRUCache, |
3362 | CacheInconsistencyError, |
3363 | ) |
3364 | +from magicicadaclient.testing.testcase import BaseTwistedTestCase |
3365 | |
3366 | |
3367 | BROKEN_PICKLE = '\axb80\x02}q\x01(U\x01aU\x04testq\x02U\x01bU\x06brokenq\x03u.' |
3368 | @@ -168,11 +163,11 @@ |
3369 | """test that each time a metadata file is updated a .old is kept""" |
3370 | self.shelf['bad_file'] = {'value': 'old'} |
3371 | path = self.shelf.key_file('bad_file') |
3372 | - self.assertFalse(path_exists(path+'.old')) |
3373 | + self.assertFalse(path_exists(path + '.old')) |
3374 | self.assertEqual({'value': 'old'}, self.shelf['bad_file']) |
3375 | # force the creation of the .old file |
3376 | self.shelf['bad_file'] = {'value': 'new'} |
3377 | - self.assertTrue(path_exists(path+'.old')) |
3378 | + self.assertTrue(path_exists(path + '.old')) |
3379 | # check that the new value is there |
3380 | self.assertEqual({'value': 'new'}, self.shelf['bad_file']) |
3381 | # write the current md file fwith 0 bytes |
3382 | @@ -183,11 +178,11 @@ |
3383 | self.shelf['broken_pickle'] = {'value': 'old'} |
3384 | path = self.shelf.key_file('broken_pickle') |
3385 | # check that .old don't exist |
3386 | - self.assertFalse(path_exists(path+'.old')) |
3387 | + self.assertFalse(path_exists(path + '.old')) |
3388 | # force the creation of the .old file |
3389 | self.shelf['broken_pickle'] = {'value': 'new'} |
3390 | # check that .old exists |
3391 | - self.assertTrue(path_exists(path+'.old')) |
3392 | + self.assertTrue(path_exists(path + '.old')) |
3393 | # check that the new value is there |
3394 | self.assertEqual({'value': 'new'}, self.shelf['broken_pickle']) |
3395 | # write random bytes to the md file |
3396 | @@ -200,10 +195,10 @@ |
3397 | """test keys() with .old and .new files around""" |
3398 | self.shelf["foo"] = "bar" |
3399 | self.shelf["foo1"] = "bar1" |
3400 | - open_file(self.shelf.key_file('foo')+'.old', 'w').close() |
3401 | - open_file(self.shelf.key_file('foo1')+'.old', 'w').close() |
3402 | - open_file(self.shelf.key_file('foo')+'.new', 'w').close() |
3403 | - open_file(self.shelf.key_file('foo1')+'.new', 'w').close() |
3404 | + open_file(self.shelf.key_file('foo') + '.old', 'w').close() |
3405 | + open_file(self.shelf.key_file('foo1') + '.old', 'w').close() |
3406 | + open_file(self.shelf.key_file('foo') + '.new', 'w').close() |
3407 | + open_file(self.shelf.key_file('foo1') + '.new', 'w').close() |
3408 | self.assertEqual(set(['foo', 'foo1']), set(self.shelf.keys())) |
3409 | |
3410 | def test_corrupted_backup(self): |
3411 | @@ -212,7 +207,7 @@ |
3412 | # create the .old backup |
3413 | self.shelf["foo"] = "bar1" |
3414 | # write 0 bytes to both |
3415 | - open_file(self.shelf.key_file('foo')+'.old', 'w').close() |
3416 | + open_file(self.shelf.key_file('foo') + '.old', 'w').close() |
3417 | open_file(self.shelf.key_file('foo'), 'w').close() |
3418 | self.assertRaises(KeyError, self.shelf.__getitem__, 'foo') |
3419 | |
3420 | @@ -233,12 +228,12 @@ |
3421 | self.shelf["foo"] = "bar1" |
3422 | path = self.shelf.key_file('foo') |
3423 | # create a .new file (a hard reboot during the rename dance) |
3424 | - open_file(path+'.new', 'w').close() |
3425 | + open_file(path + '.new', 'w').close() |
3426 | # write 0 bytes to both |
3427 | del self.shelf['foo'] |
3428 | self.assertFalse(path_exists(path)) |
3429 | - self.assertFalse(path_exists(path+'.old'), 'there is a .old file!') |
3430 | - self.assertFalse(path_exists(path+'.new'), 'there is a .new file!') |
3431 | + self.assertFalse(path_exists(path + '.old'), 'there is a .old file!') |
3432 | + self.assertFalse(path_exists(path + '.new'), 'there is a .new file!') |
3433 | |
3434 | @skipIfOS('win32', 'Skipped because code is deprecated on Windows.') |
3435 | def test_custom_unpickle(self): |
3436 | @@ -330,11 +325,11 @@ |
3437 | """overrides parent test as we have the value in the cache.""" |
3438 | self.shelf['bad_file'] = {'value': 'old'} |
3439 | path = self.shelf.key_file('bad_file') |
3440 | - self.assertFalse(path_exists(path+'.old')) |
3441 | + self.assertFalse(path_exists(path + '.old')) |
3442 | self.assertEqual({'value': 'old'}, self.shelf['bad_file']) |
3443 | # force the creation of the .old file |
3444 | self.shelf['bad_file'] = {'value': 'new'} |
3445 | - self.assertTrue(path_exists(path+'.old')) |
3446 | + self.assertTrue(path_exists(path + '.old')) |
3447 | # check that the new value is there |
3448 | self.assertEqual({'value': 'new'}, self.shelf['bad_file']) |
3449 | # write the current md file fwith 0 bytes |
3450 | @@ -346,11 +341,11 @@ |
3451 | self.shelf['broken_pickle'] = {'value': 'old'} |
3452 | path = self.shelf.key_file('broken_pickle') |
3453 | # check that .old don't exist |
3454 | - self.assertFalse(path_exists(path+'.old')) |
3455 | + self.assertFalse(path_exists(path + '.old')) |
3456 | # force the creation of the .old file |
3457 | self.shelf['broken_pickle'] = {'value': 'new'} |
3458 | # check that .old exists |
3459 | - self.assertTrue(path_exists(path+'.old')) |
3460 | + self.assertTrue(path_exists(path + '.old')) |
3461 | # check that the new value is there |
3462 | self.assertEqual({'value': 'new'}, self.shelf['broken_pickle']) |
3463 | # write random bytes to the md file |
3464 | @@ -368,7 +363,7 @@ |
3465 | """test __delitem__ method""" |
3466 | cache = LRUCache(100, 4) |
3467 | # set some data in the cache |
3468 | - values = [('key'+str(i), i) for i in range(100)] |
3469 | + values = [('key' + str(i), i) for i in range(100)] |
3470 | for i, j in values: |
3471 | cache[i] = j |
3472 | self.assertEqual(len(cache._queue), len(values)) |
3473 | @@ -378,7 +373,7 @@ |
3474 | """test __delitem__ method""" |
3475 | cache = LRUCache(100, 4) |
3476 | # set some data in the cache |
3477 | - values = [('key'+str(i), i) for i in range(100)] |
3478 | + values = [('key' + str(i), i) for i in range(100)] |
3479 | for i, j in values: |
3480 | cache[i] = j |
3481 | self.assertEqual(len(cache._queue), len(values)) |
3482 | @@ -390,7 +385,7 @@ |
3483 | def test_delitem(self): |
3484 | """test __delitem__ method""" |
3485 | cache = LRUCache(100, 4) |
3486 | - values = [('key'+str(i), i) for i in range(100)] |
3487 | + values = [('key' + str(i), i) for i in range(100)] |
3488 | for i, j in values: |
3489 | cache[i] = j |
3490 | self.assertEqual(len(cache._queue), len(values)) |
3491 | @@ -415,7 +410,7 @@ |
3492 | def test_purge(self): |
3493 | """Test the queue compact and cache purge""" |
3494 | cache = LRUCache(100, 4) |
3495 | - values = [('key'+str(i), j) for i in range(50) for j in range(8)] |
3496 | + values = [('key' + str(i), j) for i in range(50) for j in range(8)] |
3497 | for i, j in values: |
3498 | cache[i] = j |
3499 | # we hit the limit |
3500 | @@ -442,7 +437,7 @@ |
3501 | """Tests if the cache correclty keeps track of misses and hits.""" |
3502 | cache = LRUCache(100, 4) |
3503 | # set some data in the cache |
3504 | - values = [('key'+str(i), i) for i in range(10)] |
3505 | + values = [('key' + str(i), i) for i in range(10)] |
3506 | for i, j in values: |
3507 | cache[i] = j |
3508 | self.assertEqual(len(cache._queue), len(values)) |
3509 | @@ -454,7 +449,7 @@ |
3510 | self.assertEqual(cache.hits, 4) |
3511 | # try to get items not present in the cache |
3512 | for i, j in values[5:10]: |
3513 | - self.assertRaises(KeyError, cache.__getitem__, i*10) |
3514 | + self.assertRaises(KeyError, cache.__getitem__, i * 10) |
3515 | self.assertEqual(cache.misses, 5) |
3516 | |
3517 | def test_inconsistency(self): |
3518 | |
3519 | === modified file 'magicicadaclient/syncdaemon/tests/test_fsm.py' |
3520 | --- magicicadaclient/syncdaemon/tests/test_fsm.py 2018-05-19 20:44:54 +0000 |
3521 | +++ magicicadaclient/syncdaemon/tests/test_fsm.py 2018-06-03 23:09:20 +0000 |
3522 | @@ -1,6 +1,7 @@ |
3523 | # -*- coding: utf-8 -*- |
3524 | # |
3525 | # Copyright 2009-2012 Canonical Ltd. |
3526 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
3527 | # |
3528 | # This program is free software: you can redistribute it and/or modify it |
3529 | # under the terms of the GNU General Public License version 3, as published |
3530 | @@ -47,7 +48,7 @@ |
3531 | skip_if_win32_and_uses_readonly, |
3532 | ) |
3533 | |
3534 | -from ubuntuone.devtools.handlers import MementoHandler |
3535 | +from devtools.handlers import MementoHandler |
3536 | from magicicadaclient.platform import ( |
3537 | listdir, |
3538 | make_dir, |
3539 | @@ -229,7 +230,7 @@ |
3540 | self.assertEqual(mdobj.size, None) |
3541 | when = mdobj.info.created |
3542 | now = time.time() |
3543 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3544 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3545 | |
3546 | # set uuid using valid path, but not twice |
3547 | self.fsm.set_node_id(path, "uuid") |
3548 | @@ -237,7 +238,7 @@ |
3549 | mdobj = self.fsm.get_by_path(path) |
3550 | when = mdobj.info.node_id_assigned |
3551 | now = time.time() |
3552 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3553 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3554 | |
3555 | def test_with_node_id(self): |
3556 | """Test creation with node_id""" |
3557 | @@ -255,14 +256,14 @@ |
3558 | self.assertEqual(mdobj.size, None) |
3559 | when = mdobj.info.created |
3560 | now = time.time() |
3561 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3562 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3563 | |
3564 | # set uuid using valid path, but not twice |
3565 | self.assertRaises(ValueError, self.fsm.set_node_id, path, "whatever") |
3566 | mdobj = self.fsm.get_by_path(path) |
3567 | when = mdobj.info.node_id_assigned |
3568 | now = time.time() |
3569 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3570 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3571 | |
3572 | def test_invalid_args(self): |
3573 | """Test using invalid args in set_node_id.""" |
3574 | @@ -351,7 +352,7 @@ |
3575 | old_fs[k] = v |
3576 | |
3577 | # start up again, and check |
3578 | - db = Tritcask(self.tritcask_path+'.new') |
3579 | + db = Tritcask(self.tritcask_path + '.new') |
3580 | self.addCleanup(db.shutdown) |
3581 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3582 | self.fsm.vm, db) |
3583 | @@ -417,7 +418,7 @@ |
3584 | old_fs[k] = v |
3585 | |
3586 | # start up again, and check |
3587 | - db = Tritcask(self.tritcask_path+'.new') |
3588 | + db = Tritcask(self.tritcask_path + '.new') |
3589 | self.addCleanup(db.shutdown) |
3590 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3591 | self.fsm.vm, db) |
3592 | @@ -474,7 +475,7 @@ |
3593 | old_fs[k] = v |
3594 | |
3595 | # start up again, and check |
3596 | - db = Tritcask(self.tritcask_path+'.new') |
3597 | + db = Tritcask(self.tritcask_path + '.new') |
3598 | self.addCleanup(db.shutdown) |
3599 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3600 | self.fsm.vm, db) |
3601 | @@ -530,7 +531,7 @@ |
3602 | old_fs[k] = v |
3603 | |
3604 | # start up again, and check |
3605 | - db = Tritcask(self.tritcask_path+'.new') |
3606 | + db = Tritcask(self.tritcask_path + '.new') |
3607 | self.addCleanup(db.shutdown) |
3608 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3609 | self.fsm.vm, db) |
3610 | @@ -595,7 +596,7 @@ |
3611 | old_mvlimbo[k] = v |
3612 | |
3613 | # start up again, and check |
3614 | - db = Tritcask(self.tritcask_path+'.new') |
3615 | + db = Tritcask(self.tritcask_path + '.new') |
3616 | self.addCleanup(db.shutdown) |
3617 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3618 | self.fsm.vm, db) |
3619 | @@ -654,7 +655,7 @@ |
3620 | old_mvlimbo[k] = v |
3621 | |
3622 | # start up again, and check |
3623 | - db = Tritcask(self.tritcask_path+'.new') |
3624 | + db = Tritcask(self.tritcask_path + '.new') |
3625 | self.addCleanup(db.shutdown) |
3626 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3627 | self.fsm.vm, db) |
3628 | @@ -710,7 +711,7 @@ |
3629 | remove_file(version_file) |
3630 | |
3631 | # start up again, and check |
3632 | - db = Tritcask(self.tritcask_path+'.new') |
3633 | + db = Tritcask(self.tritcask_path + '.new') |
3634 | self.addCleanup(db.shutdown) |
3635 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3636 | self.fsm.vm, db) |
3637 | @@ -757,7 +758,7 @@ |
3638 | fh.write("1") |
3639 | |
3640 | # start up again, and check |
3641 | - db = Tritcask(self.tritcask_path+'.new') |
3642 | + db = Tritcask(self.tritcask_path + '.new') |
3643 | self.addCleanup(db.shutdown) |
3644 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3645 | self.fsm.vm, db) |
3646 | @@ -809,7 +810,7 @@ |
3647 | os.fsync(f.fileno()) |
3648 | |
3649 | # start up again, and check |
3650 | - db = Tritcask(self.tritcask_path+'.new') |
3651 | + db = Tritcask(self.tritcask_path + '.new') |
3652 | self.addCleanup(db.shutdown) |
3653 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3654 | self.fsm.vm, db) |
3655 | @@ -867,7 +868,7 @@ |
3656 | remove_file(version_file) |
3657 | |
3658 | # start up again, and check |
3659 | - db = Tritcask(self.tritcask_path+'.new') |
3660 | + db = Tritcask(self.tritcask_path + '.new') |
3661 | self.addCleanup(db.shutdown) |
3662 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3663 | self.fsm.vm, db) |
3664 | @@ -928,7 +929,7 @@ |
3665 | fh.write("1") |
3666 | |
3667 | # start up again, and check |
3668 | - db = Tritcask(self.tritcask_path+'.new') |
3669 | + db = Tritcask(self.tritcask_path + '.new') |
3670 | self.addCleanup(db.shutdown) |
3671 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3672 | self.fsm.vm, db) |
3673 | @@ -996,7 +997,7 @@ |
3674 | os.fsync(f.fileno()) |
3675 | |
3676 | # start up again, and check |
3677 | - db = Tritcask(self.tritcask_path+'.new') |
3678 | + db = Tritcask(self.tritcask_path + '.new') |
3679 | self.addCleanup(db.shutdown) |
3680 | newfsm = FileSystemManager(self.fsmdir, self.partials_dir, |
3681 | self.fsm.vm, db) |
3682 | @@ -1548,7 +1549,7 @@ |
3683 | """Test having similar paths (a/b, a/b1, a/b2).""" |
3684 | expected = [os.path.join('a', 'b', 'y.txt')] |
3685 | actual = sorted([d.path for d in self.fsm.get_mdobjs_in_dir( |
3686 | - os.path.join(self.share.path, 'a', 'b'))]) |
3687 | + os.path.join(self.share.path, 'a', 'b'))]) |
3688 | self.assertEqual(expected, actual) |
3689 | |
3690 | @defer.inlineCallbacks |
3691 | @@ -1719,7 +1720,7 @@ |
3692 | mdobj = self.fsm.get_by_mdid(mdid) |
3693 | when = mdobj.info.last_partial_created |
3694 | now = time.time() |
3695 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3696 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3697 | |
3698 | # invalid uuid |
3699 | self.assertRaises(KeyError, self.fsm.create_partial, "foo", "share") |
3700 | @@ -1756,7 +1757,7 @@ |
3701 | self.assertEqual(mdobj.local_hash, 9876) |
3702 | when = mdobj.info.last_downloaded |
3703 | now = time.time() |
3704 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3705 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3706 | |
3707 | # invalid uuid |
3708 | self.assertRaises( |
3709 | @@ -1796,7 +1797,7 @@ |
3710 | self.assertFalse(mdobj.info.is_partial) |
3711 | when = mdobj.info.last_partial_removed |
3712 | now = time.time() |
3713 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3714 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3715 | |
3716 | # invalid uuid |
3717 | self.assertRaises(KeyError, self.fsm.remove_partial, "foo", "share") |
3718 | @@ -1822,7 +1823,7 @@ |
3719 | mdobj = self.fsm.get_by_mdid(mdid) |
3720 | when = mdobj.info.last_partial_created |
3721 | now = time.time() |
3722 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3723 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3724 | |
3725 | # invalid uuid |
3726 | self.assertRaises(KeyError, self.fsm.create_partial, "foo", "share") |
3727 | @@ -1847,7 +1848,7 @@ |
3728 | mdobj = self.fsm.get_by_mdid(mdid) |
3729 | when = mdobj.info.last_partial_created |
3730 | now = time.time() |
3731 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3732 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3733 | |
3734 | # invalid uuid |
3735 | self.assertRaises(KeyError, self.fsm.create_partial, "foo", "share") |
3736 | @@ -1890,7 +1891,7 @@ |
3737 | self.assertFalse(mdobj.info.is_partial) |
3738 | when = mdobj.info.last_partial_removed |
3739 | now = time.time() |
3740 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3741 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3742 | |
3743 | # invalid uuid |
3744 | self.assertRaises(KeyError, self.fsm.remove_partial, "foo", "share") |
3745 | @@ -1948,7 +1949,7 @@ |
3746 | # find a almost too long file |
3747 | repeat = 300 |
3748 | while True: |
3749 | - testfile = os.path.join(self.share_path, "x"*repeat) |
3750 | + testfile = os.path.join(self.share_path, "x" * repeat) |
3751 | try: |
3752 | fh = open_file(testfile, 'w') |
3753 | except IOError, e: |
3754 | @@ -2071,7 +2072,7 @@ |
3755 | mdobj = self.fsm.get_by_mdid(mdid) |
3756 | when = mdobj.info.last_conflicted |
3757 | now = time.time() |
3758 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3759 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3760 | |
3761 | # move second time, start the .N serie |
3762 | with open_file(testfile, "w") as fh: |
3763 | @@ -2145,7 +2146,7 @@ |
3764 | self.assertEqual(mdobj.server_hash, 1234567890) |
3765 | when = mdobj.info.last_uploaded |
3766 | now = time.time() |
3767 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3768 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3769 | |
3770 | # invalid mdid |
3771 | self.assertRaises(KeyError, self.fsm.upload_finished, |
3772 | @@ -2173,7 +2174,7 @@ |
3773 | self.assertEqual(mdobj.info.last_moved_from, testfile) |
3774 | when = mdobj.info.last_moved_time |
3775 | now = time.time() |
3776 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3777 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3778 | |
3779 | # move again, to a directory |
3780 | from_path = to_path |
3781 | @@ -2244,7 +2245,7 @@ |
3782 | self.assertEqual(mdobj.info.last_moved_from, from_path) |
3783 | when = mdobj.info.last_moved_time |
3784 | now = time.time() |
3785 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3786 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3787 | |
3788 | # move again, to a directory |
3789 | from_path = to_path |
3790 | @@ -2257,7 +2258,7 @@ |
3791 | self.assertEqual(mdobj.info.last_moved_from, from_path) |
3792 | when = mdobj.info.last_moved_time |
3793 | now = time.time() |
3794 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3795 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3796 | |
3797 | def test_move_file_withfulldir(self): |
3798 | """Test that a dir is moved from even having a file inside.""" |
3799 | @@ -2288,7 +2289,7 @@ |
3800 | self.assertEqual(mdobj.info.last_moved_from, from_path) |
3801 | when = mdobj.info.last_moved_time |
3802 | now = time.time() |
3803 | - self.assertTrue(now-3 <= when <= now) # 3 seconds test range |
3804 | + self.assertTrue(now - 3 <= when <= now) # 3 seconds test range |
3805 | |
3806 | # check that file inside is ok |
3807 | newfilepath = os.path.join(to_path, "file.txt") |
3808 | @@ -4086,8 +4087,10 @@ |
3809 | def setUp(self): |
3810 | """Set up.""" |
3811 | yield super(OsIntegrationTests, self).setUp() |
3812 | - self.open_file = self.mocker.replace('magicicadaclient.platform.open_file') |
3813 | - self.normpath = self.mocker.replace('magicicadaclient.platform.normpath') |
3814 | + self.open_file = self.mocker.replace( |
3815 | + 'magicicadaclient.platform.open_file') |
3816 | + self.normpath = self.mocker.replace( |
3817 | + 'magicicadaclient.platform.normpath') |
3818 | self.listdir = self.mocker.replace('magicicadaclient.platform.listdir') |
3819 | |
3820 | def test_get_partial_for_writing(self): |
3821 | |
3822 | === modified file 'magicicadaclient/syncdaemon/tests/test_hashqueue.py' |
3823 | --- magicicadaclient/syncdaemon/tests/test_hashqueue.py 2018-05-19 20:44:54 +0000 |
3824 | +++ magicicadaclient/syncdaemon/tests/test_hashqueue.py 2018-06-03 23:09:20 +0000 |
3825 | @@ -41,13 +41,13 @@ |
3826 | from magicicadaprotocol.content_hash import content_hash_factory, crc32 |
3827 | from twisted.trial.unittest import TestCase as TwistedTestCase |
3828 | from twisted.internet import defer, reactor |
3829 | -from ubuntuone.devtools.handlers import MementoHandler |
3830 | -from ubuntuone.devtools.testcases import skipTest |
3831 | |
3832 | -from magicicadaclient.testing.testcase import BaseTwistedTestCase |
3833 | +from devtools.handlers import MementoHandler |
3834 | +from devtools.testcases import skipTest |
3835 | from magicicadaclient.platform import open_file, stat_path |
3836 | from magicicadaclient.syncdaemon import hash_queue |
3837 | from magicicadaclient.syncdaemon.hash_queue import HASHQUEUE_DELAY |
3838 | +from magicicadaclient.testing.testcase import BaseTwistedTestCase |
3839 | |
3840 | FAKE_TIMESTAMP = 1 |
3841 | |
3842 | @@ -244,11 +244,11 @@ |
3843 | should_be = [] |
3844 | for i in range(10): |
3845 | hasher = content_hash_factory() |
3846 | - text = "supercalifragilistico"+str(i) |
3847 | + text = "supercalifragilistico" + str(i) |
3848 | hasher.hash_object.update(text) |
3849 | - tfile = os.path.join(self.test_dir, "tfile"+str(i)) |
3850 | + tfile = os.path.join(self.test_dir, "tfile" + str(i)) |
3851 | with open_file(tfile, "wb") as fh: |
3852 | - fh.write("supercalifragilistico"+str(i)) |
3853 | + fh.write("supercalifragilistico" + str(i)) |
3854 | d = dict(path=tfile, hash=hasher.content_hash(), |
3855 | crc32=crc32(text), size=len(text), stat=stat_path(tfile)) |
3856 | should_be.append(("HQ_HASH_NEW", d)) |
3857 | @@ -262,7 +262,7 @@ |
3858 | |
3859 | # send what to hash |
3860 | for i in range(10): |
3861 | - tfile = os.path.join(self.test_dir, "tfile"+str(i)) |
3862 | + tfile = os.path.join(self.test_dir, "tfile" + str(i)) |
3863 | item = ((tfile, "mdid"), FAKE_TIMESTAMP) |
3864 | queue.put(item) |
3865 | |
3866 | @@ -554,11 +554,11 @@ |
3867 | should_be = [] |
3868 | for i in range(10): |
3869 | hasher = content_hash_factory() |
3870 | - text = "supercalifragilistico"+str(i) |
3871 | + text = "supercalifragilistico" + str(i) |
3872 | hasher.hash_object.update(text) |
3873 | - tfile = os.path.join(self.test_dir, "tfile"+str(i)) |
3874 | + tfile = os.path.join(self.test_dir, "tfile" + str(i)) |
3875 | with open_file(tfile, "wb") as fh: |
3876 | - fh.write("supercalifragilistico"+str(i)) |
3877 | + fh.write("supercalifragilistico" + str(i)) |
3878 | d = dict(path=tfile, hash=hasher.content_hash(), |
3879 | crc32=crc32(text), size=len(text), stat=stat_path(tfile)) |
3880 | should_be.append(("HQ_HASH_NEW", d)) |
3881 | @@ -569,7 +569,7 @@ |
3882 | |
3883 | # send what to hash |
3884 | for i in range(10): |
3885 | - tfile = os.path.join(self.test_dir, "tfile"+str(i)) |
3886 | + tfile = os.path.join(self.test_dir, "tfile" + str(i)) |
3887 | hq.insert(tfile, "mdid") |
3888 | |
3889 | # release the processor and check |
3890 | @@ -583,11 +583,11 @@ |
3891 | should_be = [] |
3892 | for i in range(10): |
3893 | hasher = content_hash_factory() |
3894 | - text = "supercalifragilistico"+str(i) |
3895 | + text = "supercalifragilistico" + str(i) |
3896 | hasher.hash_object.update(text) |
3897 | - tfile = os.path.join(self.test_dir, "tfile"+str(i)) |
3898 | + tfile = os.path.join(self.test_dir, "tfile" + str(i)) |
3899 | with open_file(tfile, "wb") as fh: |
3900 | - fh.write("supercalifragilistico"+str(i)) |
3901 | + fh.write("supercalifragilistico" + str(i)) |
3902 | d = dict(path=tfile, hash=hasher.content_hash(), |
3903 | crc32=crc32(text), size=len(text), stat=stat_path(tfile)) |
3904 | should_be.append(("HQ_HASH_NEW", d)) |
3905 | @@ -606,7 +606,7 @@ |
3906 | |
3907 | # send to hash twice |
3908 | for i in range(10): |
3909 | - tfile = os.path.join(self.test_dir, "tfile"+str(i)) |
3910 | + tfile = os.path.join(self.test_dir, "tfile" + str(i)) |
3911 | hq.insert(tfile, "mdid") |
3912 | hq.insert(tfile, "mdid") |
3913 | # start the hasher |
3914 | @@ -615,7 +615,7 @@ |
3915 | # insert the last item to check the uniqueness in the queue while |
3916 | # the hasher is running |
3917 | for i in range(9, 10): |
3918 | - tfile = os.path.join(self.test_dir, "tfile"+str(i)) |
3919 | + tfile = os.path.join(self.test_dir, "tfile" + str(i)) |
3920 | hq.insert(tfile, "mdid") |
3921 | |
3922 | # release the processor and check |
3923 | |
3924 | === modified file 'magicicadaclient/syncdaemon/tests/test_interaction_interfaces.py' |
3925 | --- magicicadaclient/syncdaemon/tests/test_interaction_interfaces.py 2018-05-19 20:44:54 +0000 |
3926 | +++ magicicadaclient/syncdaemon/tests/test_interaction_interfaces.py 2018-06-03 23:09:20 +0000 |
3927 | @@ -34,27 +34,14 @@ |
3928 | |
3929 | from magicicadaprotocol.protocol_pb2 import AccountInfo |
3930 | from twisted.internet import defer |
3931 | -from ubuntuone.devtools.handlers import MementoHandler |
3932 | |
3933 | -from magicicadaclient.testing.testcase import ( |
3934 | - FAKED_CREDENTIALS, |
3935 | - FakeCommand, |
3936 | - FakeDownload, |
3937 | - FakeUpload, |
3938 | - FakedObject, |
3939 | - FakeMainTestCase, |
3940 | - skipIfOS, |
3941 | -) |
3942 | +from devtools.handlers import MementoHandler |
3943 | from magicicadaclient.networkstate.networkstates import ONLINE |
3944 | from magicicadaclient.platform import make_dir, make_link |
3945 | from magicicadaclient.platform.tests.ipc.test_perspective_broker import ( |
3946 | FakeNetworkManagerState, |
3947 | ) |
3948 | -from magicicadaclient.syncdaemon import ( |
3949 | - config, |
3950 | - interaction_interfaces, |
3951 | - states, |
3952 | -) |
3953 | +from magicicadaclient.syncdaemon import config, interaction_interfaces, states |
3954 | from magicicadaclient.syncdaemon.interaction_interfaces import ( |
3955 | bool_str, |
3956 | get_share_dict, |
3957 | @@ -82,6 +69,15 @@ |
3958 | UDF, |
3959 | VolumeDoesNotExist, |
3960 | ) |
3961 | +from magicicadaclient.testing.testcase import ( |
3962 | + FAKED_CREDENTIALS, |
3963 | + FakeCommand, |
3964 | + FakeDownload, |
3965 | + FakeUpload, |
3966 | + FakedObject, |
3967 | + FakeMainTestCase, |
3968 | + skipIfOS, |
3969 | +) |
3970 | |
3971 | |
3972 | class CustomError(Exception): |
3973 | |
3974 | === modified file 'magicicadaclient/syncdaemon/tests/test_localrescan.py' |
3975 | --- magicicadaclient/syncdaemon/tests/test_localrescan.py 2018-05-19 20:44:54 +0000 |
3976 | +++ magicicadaclient/syncdaemon/tests/test_localrescan.py 2018-06-03 23:09:20 +0000 |
3977 | @@ -37,14 +37,9 @@ |
3978 | |
3979 | from magicicadaprotocol import content_hash as storage_hash, volumes |
3980 | from twisted.internet import defer, reactor |
3981 | -from ubuntuone.devtools.handlers import MementoHandler |
3982 | -from ubuntuone.devtools.testcases import skipIfOS |
3983 | |
3984 | -from magicicadaclient.testing.testcase import ( |
3985 | - BaseTwistedTestCase, |
3986 | - FakeVolumeManager, |
3987 | - skip_if_win32_and_uses_readonly, |
3988 | -) |
3989 | +from devtools.handlers import MementoHandler |
3990 | +from devtools.testcases import skipIfOS |
3991 | from magicicadaclient.platform import ( |
3992 | make_dir, |
3993 | make_link, |
3994 | @@ -68,6 +63,11 @@ |
3995 | ACCESS_LEVEL_RO, |
3996 | ACCESS_LEVEL_RW, |
3997 | ) |
3998 | +from magicicadaclient.testing.testcase import ( |
3999 | + BaseTwistedTestCase, |
4000 | + FakeVolumeManager, |
4001 | + skip_if_win32_and_uses_readonly, |
4002 | +) |
4003 | |
4004 | # our logging level |
4005 | TRACE = logging.getLevelName('TRACE') |
4006 | @@ -829,7 +829,7 @@ |
4007 | """Lot of files in a dir, and lots of dirs.""" |
4008 | # almost all known, to force the system to go deep |
4009 | dirs = "abcdefghijklmnopq" * 20 |
4010 | - for i in range(1, len(dirs)+1): |
4011 | + for i in range(1, len(dirs) + 1): |
4012 | dirpath = os.path.join(*dirs[:i]) |
4013 | self.create_node(dirpath, is_dir=True) |
4014 | basedir = os.path.join(*dirs) |
4015 | @@ -840,11 +840,11 @@ |
4016 | # some files in some dirs |
4017 | files = "rstuvwxyz" |
4018 | for f in files: |
4019 | - path = os.path.join(*dirs[:3]+f) |
4020 | - self.create_node(path, is_dir=False) |
4021 | - path = os.path.join(*dirs[:6]+f) |
4022 | - self.create_node(path, is_dir=False) |
4023 | - sh2 = os.path.join(self.share.path, *dirs[:6]+"q") |
4024 | + path = os.path.join(*dirs[:3] + f) |
4025 | + self.create_node(path, is_dir=False) |
4026 | + path = os.path.join(*dirs[:6] + f) |
4027 | + self.create_node(path, is_dir=False) |
4028 | + sh2 = os.path.join(self.share.path, *dirs[:6] + "q") |
4029 | open_file(sh2, "w").close() |
4030 | |
4031 | # scan! |
4032 | @@ -1953,7 +1953,7 @@ |
4033 | self.assertFalse(path_exists(partial_path)) |
4034 | # logged in warning |
4035 | self.assertTrue(self.handler.check_warning( |
4036 | - "Found a directory in SERVER")) |
4037 | + "Found a directory in SERVER")) |
4038 | |
4039 | def test_check_stat_None(self): |
4040 | """Test check_stat with oldstat = None.""" |
4041 | @@ -2041,7 +2041,7 @@ |
4042 | self.assertEqual(self.aq.unlinked, [(self.share.volume_id, |
4043 | "parent_id", "uuid", path, True)]) |
4044 | self.assertTrue(self.handler.check_info( |
4045 | - "generating Unlink from trash")) |
4046 | + "generating Unlink from trash")) |
4047 | |
4048 | @defer.inlineCallbacks |
4049 | def test_trash_two(self): |
4050 | |
4051 | === modified file 'magicicadaclient/syncdaemon/tests/test_logger.py' |
4052 | --- magicicadaclient/syncdaemon/tests/test_logger.py 2018-05-19 20:44:54 +0000 |
4053 | +++ magicicadaclient/syncdaemon/tests/test_logger.py 2018-06-03 23:09:20 +0000 |
4054 | @@ -1,8 +1,7 @@ |
4055 | # -*- coding: utf-8 -*- |
4056 | # |
4057 | -# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> |
4058 | -# |
4059 | # Copyright 2009-2012 Canonical Ltd. |
4060 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
4061 | # |
4062 | # This program is free software: you can redistribute it and/or modify it |
4063 | # under the terms of the GNU General Public License version 3, as published |
4064 | @@ -37,9 +36,8 @@ |
4065 | from twisted.internet import defer |
4066 | from twisted.trial import unittest |
4067 | |
4068 | -from ubuntuone.devtools.handlers import MementoHandler |
4069 | -from ubuntuone.devtools.testcases import skipIfOS |
4070 | - |
4071 | +from devtools.handlers import MementoHandler |
4072 | +from devtools.testcases import skipIfOS |
4073 | from magicicadaclient.syncdaemon.logger import ( |
4074 | DebugCapture, |
4075 | NOTE, |
4076 | @@ -302,7 +300,7 @@ |
4077 | self.handler.addFilter(MultiFilter([self.__class__.__name__])) |
4078 | self.logger.debug('this msg should be logged') |
4079 | self.assertEqual(1, len(self.handler.records)) |
4080 | - other_logger = logging.getLogger("NO_LOG."+self.__class__.__name__) |
4081 | + other_logger = logging.getLogger("NO_LOG." + self.__class__.__name__) |
4082 | other_logger.debug('this msg shouldn\'t be logged') |
4083 | self.assertEqual(1, len(self.handler.records)) |
4084 | |
4085 | @@ -311,7 +309,7 @@ |
4086 | self.handler.addFilter( |
4087 | MultiFilter([self.__class__.__name__, |
4088 | self.__class__.__name__ + ".child"])) |
4089 | - no_logger = logging.getLogger("NO_LOG."+self.__class__.__name__) |
4090 | + no_logger = logging.getLogger("NO_LOG." + self.__class__.__name__) |
4091 | yes_logger = logging.getLogger(self.__class__.__name__ + '.child') |
4092 | self.logger.debug('this msg should be logged') |
4093 | self.assertEqual(1, len(self.handler.records)) |
4094 | |
4095 | === modified file 'magicicadaclient/syncdaemon/tests/test_main.py' |
4096 | --- magicicadaclient/syncdaemon/tests/test_main.py 2018-05-19 20:44:54 +0000 |
4097 | +++ magicicadaclient/syncdaemon/tests/test_main.py 2018-06-03 23:09:20 +0000 |
4098 | @@ -33,15 +33,12 @@ |
4099 | import os |
4100 | |
4101 | from twisted.internet import defer, reactor |
4102 | -from ubuntuone.devtools.handlers import MementoHandler |
4103 | -from magicicadaclient.platform import expand_user |
4104 | |
4105 | -from magicicadaclient.testing.testcase import ( |
4106 | - BaseTwistedTestCase, FAKED_CREDENTIALS, FakeMonitor |
4107 | -) |
4108 | +from devtools.handlers import MementoHandler |
4109 | from magicicadaclient.clientdefs import VERSION |
4110 | from magicicadaclient.logger import NOTE |
4111 | from magicicadaclient.platform import ( |
4112 | + expand_user, |
4113 | is_link, |
4114 | make_dir, |
4115 | make_link, |
4116 | @@ -49,6 +46,9 @@ |
4117 | remove_dir, |
4118 | ) |
4119 | from magicicadaclient.syncdaemon import main as main_mod |
4120 | +from magicicadaclient.testing.testcase import ( |
4121 | + BaseTwistedTestCase, FAKED_CREDENTIALS, FakeMonitor |
4122 | +) |
4123 | |
4124 | |
4125 | class FakeListener(object): |
4126 | |
4127 | === modified file 'magicicadaclient/syncdaemon/tests/test_offloadqueue.py' |
4128 | --- magicicadaclient/syncdaemon/tests/test_offloadqueue.py 2018-05-19 20:44:54 +0000 |
4129 | +++ magicicadaclient/syncdaemon/tests/test_offloadqueue.py 2018-06-03 23:09:20 +0000 |
4130 | @@ -1,6 +1,7 @@ |
4131 | # -*- coding: utf-8 -*- |
4132 | # |
4133 | # Copyright 2012 Canonical Ltd. |
4134 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
4135 | # |
4136 | # This program is free software: you can redistribute it and/or modify it |
4137 | # under the terms of the GNU General Public License version 3, as published |
4138 | @@ -36,10 +37,10 @@ |
4139 | |
4140 | from twisted.trial.unittest import TestCase as TwistedTestCase |
4141 | |
4142 | -from ubuntuone.devtools.handlers import MementoHandler |
4143 | -from magicicadaclient.syncdaemon.offload_queue import OffloadQueue, STRUCT_SIZE |
4144 | +from devtools.handlers import MementoHandler |
4145 | from magicicadaclient.syncdaemon.interfaces import IMarker |
4146 | from magicicadaclient.syncdaemon.marker import MDMarker |
4147 | +from magicicadaclient.syncdaemon.offload_queue import OffloadQueue, STRUCT_SIZE |
4148 | |
4149 | |
4150 | class OffloadQueueTestCase(TwistedTestCase): |
4151 | |
4152 | === modified file 'magicicadaclient/syncdaemon/tests/test_pathlockingtree.py' |
4153 | --- magicicadaclient/syncdaemon/tests/test_pathlockingtree.py 2018-05-19 20:44:54 +0000 |
4154 | +++ magicicadaclient/syncdaemon/tests/test_pathlockingtree.py 2018-06-03 23:09:20 +0000 |
4155 | @@ -1,8 +1,5 @@ |
4156 | -# ubuntuone.syncdaemon.tests.test_pathlockingtree - PathLockingTree tests |
4157 | -# |
4158 | -# Author: Facundo Batista <facundo@canonical.com> |
4159 | -# |
4160 | # Copyright 2011-2012 Canonical Ltd. |
4161 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
4162 | # |
4163 | # This program is free software: you can redistribute it and/or modify it |
4164 | # under the terms of the GNU General Public License version 3, as published |
4165 | @@ -35,7 +32,7 @@ |
4166 | from twisted.internet import defer |
4167 | from twisted.trial.unittest import TestCase as TwistedTestCase |
4168 | |
4169 | -from ubuntuone.devtools.handlers import MementoHandler |
4170 | +from devtools.handlers import MementoHandler |
4171 | from magicicadaclient.syncdaemon.action_queue import PathLockingTree |
4172 | |
4173 | |
4174 | |
4175 | === modified file 'magicicadaclient/syncdaemon/tests/test_sync.py' |
4176 | --- magicicadaclient/syncdaemon/tests/test_sync.py 2018-05-19 20:44:54 +0000 |
4177 | +++ magicicadaclient/syncdaemon/tests/test_sync.py 2018-06-03 23:09:20 +0000 |
4178 | @@ -43,15 +43,9 @@ |
4179 | from magicicadaprotocol.request import ROOT |
4180 | from twisted.internet import defer |
4181 | from twisted.python.failure import Failure |
4182 | -from ubuntuone.devtools.handlers import MementoHandler |
4183 | -from ubuntuone.devtools.testcases import skipIfOS |
4184 | |
4185 | -from magicicadaclient.testing.testcase import ( |
4186 | - FakeMain, |
4187 | - FakeVolumeManager, |
4188 | - BaseTwistedTestCase, |
4189 | - Listener, |
4190 | -) |
4191 | +from devtools.handlers import MementoHandler |
4192 | +from devtools.testcases import skipIfOS |
4193 | from magicicadaclient.platform import ( |
4194 | make_dir, |
4195 | open_file, |
4196 | @@ -61,10 +55,20 @@ |
4197 | from magicicadaclient.syncdaemon.filesystem_manager import FileSystemManager |
4198 | from magicicadaclient.syncdaemon.tritcask import Tritcask |
4199 | from magicicadaclient.syncdaemon.fsm import fsm as fsm_module |
4200 | -from magicicadaclient.syncdaemon.sync import FSKey, Sync, SyncStateMachineRunner |
4201 | +from magicicadaclient.syncdaemon.sync import ( |
4202 | + FSKey, |
4203 | + Sync, |
4204 | + SyncStateMachineRunner, |
4205 | +) |
4206 | from magicicadaclient.syncdaemon.volume_manager import Share |
4207 | from magicicadaclient.syncdaemon.event_queue import EventQueue, EVENTS |
4208 | from magicicadaclient.syncdaemon.marker import MDMarker |
4209 | +from magicicadaclient.testing.testcase import ( |
4210 | + FakeMain, |
4211 | + FakeVolumeManager, |
4212 | + BaseTwistedTestCase, |
4213 | + Listener, |
4214 | +) |
4215 | |
4216 | |
4217 | class TestSyncClassAPI(unittest.TestCase): |
4218 | |
4219 | === modified file 'magicicadaclient/syncdaemon/tests/test_tritcask.py' |
4220 | --- magicicadaclient/syncdaemon/tests/test_tritcask.py 2018-05-19 20:44:54 +0000 |
4221 | +++ magicicadaclient/syncdaemon/tests/test_tritcask.py 2018-06-03 23:09:20 +0000 |
4222 | @@ -1,8 +1,5 @@ |
4223 | -# tests.syncdaemon.test_tritcask - tritcask tests |
4224 | -# |
4225 | -# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> |
4226 | -# |
4227 | # Copyright 2010-2012 Canonical Ltd. |
4228 | +# Copyright 2018 Chicharreros (https://launchpad.net/~chicharreros) |
4229 | # |
4230 | # This program is free software: you can redistribute it and/or modify it |
4231 | # under the terms of the GNU General Public License version 3, as published |
4232 | @@ -42,8 +39,8 @@ |
4233 | from operator import attrgetter |
4234 | from twisted.internet import defer |
4235 | |
4236 | +from devtools.handlers import MementoHandler |
4237 | from magicicadaclient.testing.testcase import BaseTwistedTestCase |
4238 | -from ubuntuone.devtools.handlers import MementoHandler |
4239 | from magicicadaclient.syncdaemon import tritcask |
4240 | from magicicadaclient.syncdaemon.tritcask import ( |
4241 | TOMBSTONE, |
4242 | @@ -343,7 +340,7 @@ |
4243 | fd.read(crc32_size + 4) |
4244 | fd.truncate() |
4245 | # write a different value -> random bytes |
4246 | - fd.write(os.urandom(header_size/2)) |
4247 | + fd.write(os.urandom(header_size / 2)) |
4248 | fd.flush() |
4249 | fmap = mmap.mmap(fd.fileno(), 0, access=mmap.ACCESS_READ) |
4250 | with contextlib.closing(fmap): |
4251 | @@ -1377,7 +1374,7 @@ |
4252 | # check that the TOMBSTONE is there for these keys |
4253 | with open(self.db.live_file.filename, 'r+b') as f: |
4254 | raw_data_len = len(key) + len(TOMBSTONE) + crc32_size + header_size |
4255 | - f.seek(-1*raw_data_len, os.SEEK_END) |
4256 | + f.seek(-1 * raw_data_len, os.SEEK_END) |
4257 | raw_data = f.read(raw_data_len) |
4258 | self.assertEqual(TOMBSTONE, |
4259 | raw_data[crc32_size + header_size + len(key):]) |
4260 | @@ -1743,9 +1740,10 @@ |
4261 | for i in range(20): |
4262 | keydir[(0, str(uuid.uuid4()))] = KeydirEntry( |
4263 | file_id_1, timestamp(), len(str(uuid.uuid4())), i + 10) |
4264 | - entry_size = len(str(uuid.uuid4()))*2 + header_size + crc32_size |
4265 | - self.assertEqual(entry_size*10, keydir._stats[file_id]['live_bytes']) |
4266 | - self.assertEqual(entry_size*20, keydir._stats[file_id_1]['live_bytes']) |
4267 | + entry_size = len(str(uuid.uuid4())) * 2 + header_size + crc32_size |
4268 | + self.assertEqual(entry_size * 10, keydir._stats[file_id]['live_bytes']) |
4269 | + self.assertEqual( |
4270 | + entry_size * 20, keydir._stats[file_id_1]['live_bytes']) |
4271 | |
4272 | def test_update_entry(self): |
4273 | """Test that __setitem__ updates the stats for an entry.""" |
4274 | @@ -1796,10 +1794,10 @@ |
4275 | len(str(uuid.uuid4())), i + 10) |
4276 | if i % 2: |
4277 | keydir.remove((0, key)) |
4278 | - entry_size = len(str(uuid.uuid4()))*2 + header_size + crc32_size |
4279 | - self.assertEqual(entry_size*(10/2), |
4280 | + entry_size = len(str(uuid.uuid4())) * 2 + header_size + crc32_size |
4281 | + self.assertEqual(entry_size * (10 / 2), |
4282 | keydir._stats[file_id]['live_bytes']) |
4283 | - self.assertEqual(entry_size*(20/2), |
4284 | + self.assertEqual(entry_size * (20 / 2), |
4285 | keydir._stats[file_id_1]['live_bytes']) |
4286 | |
4287 | def test_remove_missing_key(self): |
4288 | |
4289 | === modified file 'magicicadaclient/syncdaemon/tests/test_vm.py' |
4290 | --- magicicadaclient/syncdaemon/tests/test_vm.py 2018-05-19 20:44:54 +0000 |
4291 | +++ magicicadaclient/syncdaemon/tests/test_vm.py 2018-06-03 23:09:20 +0000 |
4292 | @@ -45,15 +45,16 @@ |
4293 | |
4294 | from mocker import Mocker, MATCH |
4295 | from twisted.internet import defer, reactor |
4296 | -from ubuntuone.devtools.handlers import MementoHandler |
4297 | -from ubuntuone.devtools.testcases import skipIfOS |
4298 | |
4299 | -from magicicadaclient.testing.testcase import ( |
4300 | - BaseTwistedTestCase, |
4301 | - FakeMain, |
4302 | -) |
4303 | +from devtools.handlers import MementoHandler |
4304 | +from devtools.testcases import skipIfOS |
4305 | from magicicadaclient import platform |
4306 | -from magicicadaclient.syncdaemon import config, event_queue, tritcask, volume_manager |
4307 | +from magicicadaclient.syncdaemon import ( |
4308 | + config, |
4309 | + event_queue, |
4310 | + tritcask, |
4311 | + volume_manager, |
4312 | +) |
4313 | from magicicadaclient.syncdaemon.volume_manager import ( |
4314 | ACCESS_LEVEL_RO, |
4315 | ACCESS_LEVEL_RW, |
4316 | @@ -83,6 +84,7 @@ |
4317 | set_dir_readonly, |
4318 | set_dir_readwrite, |
4319 | ) |
4320 | +from magicicadaclient.testing.testcase import BaseTwistedTestCase, FakeMain |
4321 | |
4322 | # grab the metadata version before tests fiddle with it |
4323 | CURRENT_METADATA_VERSION = VolumeManager.METADATA_VERSION |
4324 | @@ -2760,7 +2762,7 @@ |
4325 | root_volume = volumes.RootVolume(uuid.uuid4(), None, 10) |
4326 | d = defer.Deferred() |
4327 | self.vm._got_root = lambda node_id, free_bytes: d.callback( |
4328 | - (node_id, free_bytes)) |
4329 | + (node_id, free_bytes)) |
4330 | self.main.event_q.push('AQ_LIST_VOLUMES', volumes=[root_volume]) |
4331 | root_node_id, free_bytes = yield d |
4332 | self.assertEqual(str(root_volume.node_id), root_node_id) |
4333 | @@ -4172,7 +4174,7 @@ |
4334 | self.patch(VolumeManager, "METADATA_VERSION", self.fake_version) |
4335 | self.temp_dir = os.path.join(self.mktemp(), u"Ñandú") |
4336 | self.version_file = os.path.join(self.temp_dir, ".version").encode( |
4337 | - sys.getfilesystemencoding()) |
4338 | + sys.getfilesystemencoding()) |
4339 | self.md_upgrader = MetadataUpgrader(self.temp_dir.encode("utf-8"), |
4340 | "", "", "", "", "", "", None) |
4341 | |
4342 | |
4343 | === modified file 'magicicadaclient/testing/testcase.py' |
4344 | --- magicicadaclient/testing/testcase.py 2018-05-19 20:44:54 +0000 |
4345 | +++ magicicadaclient/testing/testcase.py 2018-06-03 23:09:20 +0000 |
4346 | @@ -43,10 +43,10 @@ |
4347 | |
4348 | from twisted.internet import defer |
4349 | from twisted.trial.unittest import TestCase as TwistedTestCase |
4350 | -from ubuntuone.devtools.testcases import skipIfOS |
4351 | from zope.interface import implements |
4352 | from zope.interface.verify import verifyObject |
4353 | |
4354 | +from devtools.testcases import skipIfOS |
4355 | from magicicadaclient.syncdaemon import ( |
4356 | config, |
4357 | action_queue, |
4358 | |
4359 | === modified file 'magicicadaclient/utils/__init__.py' |
4360 | --- magicicadaclient/utils/__init__.py 2016-06-04 21:14:35 +0000 |
4361 | +++ magicicadaclient/utils/__init__.py 2018-06-03 23:09:20 +0000 |
4362 | @@ -73,8 +73,8 @@ |
4363 | |
4364 | # otherwise, try to load 'dir_constant' from installation path |
4365 | try: |
4366 | - __import__('ubuntuone.clientdefs', None, None, ['']) |
4367 | - module = sys.modules.get('ubuntuone.clientdefs') |
4368 | + __import__('magicicadaclient.clientdefs', None, None, ['']) |
4369 | + module = sys.modules.get('magicicadaclient.clientdefs') |
4370 | return getattr(module, dir_constant) |
4371 | except (ImportError, AttributeError): |
4372 | msg = '_get_dir: can not build a valid path. Giving up. ' \ |
4373 | @@ -135,8 +135,7 @@ |
4374 | |
4375 | if getattr(sys, "frozen", None) is not None: |
4376 | if sys.platform == "win32": |
4377 | - ssl_cert_location = list(load_config_paths( |
4378 | - "ubuntuone"))[1] |
4379 | + ssl_cert_location = list(load_config_paths("ubuntuone"))[1] |
4380 | elif sys.platform == "darwin": |
4381 | main_app_dir = "".join(__file__.partition(".app")[:-1]) |
4382 | main_app_resources_dir = os.path.join(main_app_dir, |
4383 | |
4384 | === modified file 'magicicadaclient/utils/tests/test_common.py' |
4385 | --- magicicadaclient/utils/tests/test_common.py 2018-05-19 20:44:54 +0000 |
4386 | +++ magicicadaclient/utils/tests/test_common.py 2018-06-03 23:09:20 +0000 |
4387 | @@ -1,7 +1,7 @@ |
4388 | # -*- coding: utf-8 -*- |
4389 | # |
4390 | # Copyright 2011-2012 Canonical Ltd. |
4391 | -# Copyright 2015-2017 Chicharreros (https://launchpad.net/~chicharreros) |
4392 | +# Copyright 2015-2018 Chicharreros (https://launchpad.net/~chicharreros) |
4393 | # |
4394 | # This program is free software: you can redistribute it and/or modify it |
4395 | # under the terms of the GNU General Public License version 3, as published |
4396 | @@ -38,13 +38,13 @@ |
4397 | |
4398 | from twisted.internet import defer |
4399 | from twisted.web import resource |
4400 | -from ubuntuone.devtools.handlers import MementoHandler |
4401 | -from ubuntuone.devtools.testing.txwebserver import HTTPWebServer |
4402 | |
4403 | +from devtools.handlers import MementoHandler |
4404 | +from devtools.testing.txwebserver import HTTPWebServer |
4405 | from magicicadaclient import utils |
4406 | from magicicadaclient.tests import TestCase |
4407 | |
4408 | -CONSTANTS_MODULE = 'ubuntuone.clientdefs' |
4409 | +CONSTANTS_MODULE = 'magicicadaclient.clientdefs' |
4410 | NOT_DEFINED = object() |
4411 | |
4412 | |
4413 | |
4414 | === modified file 'magicicadaclient/utils/tests/test_ipc.py' |
4415 | --- magicicadaclient/utils/tests/test_ipc.py 2018-05-19 20:44:54 +0000 |
4416 | +++ magicicadaclient/utils/tests/test_ipc.py 2018-06-03 23:09:20 +0000 |
4417 | @@ -1,7 +1,7 @@ |
4418 | # -*- coding: utf-8 -*- |
4419 | # |
4420 | # Copyright 2011-2012 Canonical Ltd. |
4421 | -# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros) |
4422 | +# Copyright 2015-2018 Chicharreros (https://launchpad.net/~chicharreros) |
4423 | # |
4424 | # This program is free software: you can redistribute it and/or modify it |
4425 | # under the terms of the GNU General Public License version 3, as published |
4426 | @@ -39,13 +39,13 @@ |
4427 | DeadReferenceError, |
4428 | NoSuchMethod, |
4429 | ) |
4430 | -from ubuntuone.devtools.handlers import MementoHandler |
4431 | -from ubuntuone.devtools.testcases import skipIfOS |
4432 | -from ubuntuone.devtools.testcases.txsocketserver import ( |
4433 | + |
4434 | +from devtools.handlers import MementoHandler |
4435 | +from devtools.testcases import skipIfOS |
4436 | +from devtools.testcases.txsocketserver import ( |
4437 | TidyUnixServer, |
4438 | TCPPbServerTestCase, |
4439 | ) |
4440 | - |
4441 | from magicicadaclient.tests import TestCase |
4442 | from magicicadaclient.utils import ipc |
4443 | |
4444 | |
4445 | === modified file 'magicicadaclient/utils/tests/test_tcpactivation.py' |
4446 | --- magicicadaclient/utils/tests/test_tcpactivation.py 2018-05-19 20:44:54 +0000 |
4447 | +++ magicicadaclient/utils/tests/test_tcpactivation.py 2018-06-03 23:09:20 +0000 |
4448 | @@ -1,7 +1,7 @@ |
4449 | # -*- coding: utf-8 -*- |
4450 | # |
4451 | # Copyright 2011-2012 Canonical Ltd. |
4452 | -# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros) |
4453 | +# Copyright 2015-2018 Chicharreros (https://launchpad.net/~chicharreros) |
4454 | # |
4455 | # This program is free software: you can redistribute it and/or modify it |
4456 | # under the terms of the GNU General Public License version 3, as published |
4457 | @@ -36,11 +36,8 @@ |
4458 | from twisted.internet import defer, protocol, task |
4459 | from twisted.trial.unittest import TestCase |
4460 | |
4461 | -from ubuntuone.devtools.testcases.txsocketserver import ( |
4462 | - ServerTestCase, |
4463 | - TidyTCPServer, |
4464 | -) |
4465 | |
4466 | +from devtools.testcases.txsocketserver import ServerTestCase, TidyTCPServer |
4467 | from magicicadaclient.utils import tcpactivation |
4468 | from magicicadaclient.utils.tcpactivation import ( |
4469 | ActivationClient, |
4470 | |
4471 | === modified file 'magicicadaclient/utils/tests/test_translation.py' |
4472 | --- magicicadaclient/utils/tests/test_translation.py 2018-05-19 20:44:54 +0000 |
4473 | +++ magicicadaclient/utils/tests/test_translation.py 2018-06-03 23:09:20 +0000 |
4474 | @@ -34,8 +34,8 @@ |
4475 | import sys |
4476 | |
4477 | from twisted.internet import defer |
4478 | -from ubuntuone.devtools.testcases import TestCase, skipIfNotOS |
4479 | |
4480 | +from devtools.testcases import TestCase, skipIfNotOS |
4481 | from magicicadaclient.utils import translation |
4482 | |
4483 | TEST_DOMAIN = 'test-domain' |
4484 | |
4485 | === modified file 'magicicadaclient/utils/tests/test_txsecrets.py' |
4486 | --- magicicadaclient/utils/tests/test_txsecrets.py 2018-05-19 20:44:54 +0000 |
4487 | +++ magicicadaclient/utils/tests/test_txsecrets.py 2018-06-03 23:09:20 +0000 |
4488 | @@ -1,7 +1,7 @@ |
4489 | # -*- coding: utf-8 -*- |
4490 | # |
4491 | # Copyright 2010-2012 Canonical Ltd. |
4492 | -# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros) |
4493 | +# Copyright 2015-2018 Chicharreros (https://launchpad.net/~chicharreros) |
4494 | # |
4495 | # This program is free software: you can redistribute it and/or modify it |
4496 | # under the terms of the GNU General Public License version 3, as published |
4497 | @@ -36,8 +36,8 @@ |
4498 | import dbus.service |
4499 | |
4500 | from twisted.internet.defer import inlineCallbacks, returnValue |
4501 | -from ubuntuone.devtools.testcases.dbus import DBusTestCase |
4502 | |
4503 | +from devtools.testcases.dbus import DBusTestCase |
4504 | from magicicadaclient.utils import txsecrets |
4505 | |
4506 | KEY_TYPE_ATTR = {"key-type": "Foo credentials"} |
4507 | |
4508 | === modified file 'requirements-devel.txt' |
4509 | --- requirements-devel.txt 2018-03-18 15:03:09 +0000 |
4510 | +++ requirements-devel.txt 2018-06-03 23:09:20 +0000 |
4511 | @@ -1,1 +1,3 @@ |
4512 | +coverage==3.7.1 |
4513 | flake8==3.5.0 |
4514 | +mocker==1.1.1 |
4515 | |
4516 | === modified file 'requirements.txt' |
4517 | --- requirements.txt 2018-04-14 23:34:20 +0000 |
4518 | +++ requirements.txt 2018-06-03 23:09:20 +0000 |
4519 | @@ -1,2 +1,7 @@ |
4520 | +configglue==1.1.3.post0 |
4521 | +dbus-python==1.2.8 |
4522 | +magicicadaprotocol==2.0 |
4523 | +PyGObject==3.28.2 |
4524 | +pyinotify==0.9.6 |
4525 | Send2Trash==1.5.0 |
4526 | -magicicadaprotocol==2.0 |
4527 | +Twisted==18.4.0 |
4528 | |
4529 | === modified file 'run-tests' |
4530 | --- run-tests 2018-05-19 20:44:54 +0000 |
4531 | +++ run-tests 2018-06-03 23:09:20 +0000 |
4532 | @@ -49,5 +49,5 @@ |
4533 | |
4534 | echo "*** Running test suite for ""$MODULE"" ***" |
4535 | export SSL_CERTIFICATES_DIR=/etc/ssl/certs |
4536 | -.env/bin/python /usr/bin/u1trial -i "$IGNORE_FILES" -p "$IGNORE_PATHS" $MODULE |
4537 | +.env/bin/python contrib/u1trial -i "$IGNORE_FILES" -p "$IGNORE_PATHS" $MODULE |
4538 | rm -rf _trial_temp |
4539 | |
4540 | === modified file 'setup.py' |
4541 | --- setup.py 2018-05-31 16:29:41 +0000 |
4542 | +++ setup.py 2018-06-03 23:09:20 +0000 |
4543 | @@ -32,15 +32,9 @@ |
4544 | import os |
4545 | import sys |
4546 | |
4547 | -try: |
4548 | - from DistUtilsExtra.command import build_extra, build_i18n |
4549 | - import DistUtilsExtra.auto |
4550 | -except ImportError: |
4551 | - print >> sys.stderr, 'To build this program you need '\ |
4552 | - 'https://launchpad.net/python-distutils-extra' |
4553 | - raise |
4554 | -assert DistUtilsExtra.auto.__version__ >= '2.18', \ |
4555 | - 'needs DistUtilsExtra.auto >= 2.18' |
4556 | +from setuptools import setup |
4557 | +from setuptools.command.install import install |
4558 | +from distutils.command import build, clean |
4559 | |
4560 | |
4561 | PROJECT_NAME = 'magicicada-client' |
4562 | @@ -83,7 +77,7 @@ |
4563 | out_file.write(content) |
4564 | |
4565 | |
4566 | -class Install(DistUtilsExtra.auto.install_auto): |
4567 | +class Install(install): |
4568 | """Class to install proper files.""" |
4569 | |
4570 | def run(self): |
4571 | @@ -110,7 +104,8 @@ |
4572 | prefix = self.install_data.replace( |
4573 | self.root if self.root is not None else '', '') |
4574 | replace_variables(SERVICE_FILES, prefix) |
4575 | - DistUtilsExtra.auto.install_auto.run(self) |
4576 | + install.run(self) |
4577 | + |
4578 | # Replace the CLIENTDEFS paths here, so that we can do it directly in |
4579 | # the installed copy, rather than the lcoal copy. This allows us to |
4580 | # have a semi-generated version for use in tests, and a full version |
4581 | @@ -127,7 +122,7 @@ |
4582 | out_file.write(content) |
4583 | |
4584 | |
4585 | -class Build(build_extra.build_extra): |
4586 | +class Build(build.build): |
4587 | """Build PyQt (.ui) files and resources.""" |
4588 | |
4589 | description = "build PyQt GUIs (.ui) and resources (.qrc)" |
4590 | @@ -135,10 +130,10 @@ |
4591 | def run(self): |
4592 | """Execute the command.""" |
4593 | replace_variables(BUILD_FILES) |
4594 | - build_extra.build_extra.run(self) |
4595 | - |
4596 | - |
4597 | -class Clean(DistUtilsExtra.auto.clean_build_tree): |
4598 | + build.build.run(self) |
4599 | + |
4600 | + |
4601 | +class Clean(clean.clean): |
4602 | """Class to clean up after the build.""" |
4603 | |
4604 | def run(self): |
4605 | @@ -147,24 +142,7 @@ |
4606 | if os.path.exists(built_file): |
4607 | os.unlink(built_file) |
4608 | |
4609 | - DistUtilsExtra.auto.clean_build_tree.run(self) |
4610 | - |
4611 | - |
4612 | -class BuildLocale(build_i18n.build_i18n): |
4613 | - """Work around a bug in DistUtilsExtra.""" |
4614 | - |
4615 | - def run(self): |
4616 | - """Magic.""" |
4617 | - build_i18n.build_i18n.run(self) |
4618 | - i = 0 |
4619 | - for df in self.distribution.data_files: |
4620 | - if df[0].startswith('etc/xdg/'): |
4621 | - if sys.platform not in ('darwin', 'win32'): |
4622 | - new_df = (df[0].replace('etc/xdg/', '/etc/xdg/'), df[1]) |
4623 | - self.distribution.data_files[i] = new_df |
4624 | - else: |
4625 | - self.distribution.data_files.pop(i) |
4626 | - i += 1 |
4627 | + clean.clean.run(self) |
4628 | |
4629 | |
4630 | def set_py2exe_paths(): |
4631 | @@ -191,10 +169,9 @@ |
4632 | |
4633 | |
4634 | cmdclass = { |
4635 | - 'install': Install, |
4636 | 'build': Build, |
4637 | 'clean': Clean, |
4638 | - 'build_i18n': BuildLocale, |
4639 | + 'install': Install, |
4640 | } |
4641 | |
4642 | bin_scripts = [ |
4643 | @@ -236,7 +213,7 @@ |
4644 | scripts.extend(bin_scripts) |
4645 | extra = {} |
4646 | |
4647 | -DistUtilsExtra.auto.setup( |
4648 | +setup( |
4649 | name=PROJECT_NAME, |
4650 | version=VERSION, |
4651 | license='GPL v3', |
20:43 < nessita> revisé tu branch, todo ok, pero no entiendo cómo anda "from devtools import..." porque no veo que nadie meta contrib en el pythonpath
20:44 < nessita> (y de elegir, preferiría que los imports sean from contrib.devtools ...)
20:45 < Facu> nessita, hola! no sé, todo lo que puse en contrib se importó solo, así que ahí no toqué nada
20:46 < Facu>| digo, ese mecanismo ya estaba de antes
20:48 < nessita> Facu, lo puedo landear así pero me da cosa que no veo quien carajo lo mete en el pythonpath
21:02 < Facu> nessita, +1 a "sacar eso", pero se podría hacer después; en cualquier caso, tenemos cosas más "urgentes" para hacer, yo ni le pondría prioridad
21:03 < nessita> okis