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