Merge lp:~nuclearbob/utah/various-fixes into lp:utah
- various-fixes
- Merge into dev
Status: | Merged |
---|---|
Approved by: | Javier Collado |
Approved revision: | 889 |
Merged at revision: | 893 |
Proposed branch: | lp:~nuclearbob/utah/various-fixes |
Merge into: | lp:utah |
Diff against target: |
1456 lines (+190/-729) 19 files modified
distribute_setup.py (+0/-485) docs/source/reference.rst (+6/-26) examples/run_utah_tests.py (+1/-1) setup.py (+7/-5) tests/__init__.py (+16/-0) tests/test_rsyslog.py (+1/-1) utah/client/common.py (+4/-3) utah/client/tests/test_runner.py (+32/-23) utah/client/tests/test_testcase.py (+22/-13) utah/client/tests/test_testsuite.py (+29/-12) utah/client/tests/test_vcs_git.py (+1/-0) utah/provisioning/baremetal/inventory.py (+4/-3) utah/provisioning/inventory.py (+58/-2) utah/provisioning/inventory/__init__.py (+0/-16) utah/provisioning/inventory/exceptions.py (+0/-26) utah/provisioning/inventory/sqlite.py (+0/-69) utah/provisioning/vm.py (+9/-2) utah/provisioning/vm/__init__.py (+0/-16) utah/provisioning/vm/exceptions.py (+0/-26) |
To merge this branch: | bzr merge lp:~nuclearbob/utah/various-fixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Javier Collado (community) | Approve | ||
Max Brustkern (community) | Needs Resubmitting | ||
Review via email:
|
Commit message
Description of the change
This branch adds an init file to the tests directory so we can import tests.common so the server self tests can pass. I wonder if these tests should be in a different place at some point?
Also, I fixed a bunch of static analysis errors. Docstrings for many new tests were not imperative, so I tried to make them consistent since pep257 complained about some of them.
The last change adds a git config command to set the email address so that the git test can run on a system where the user has never configured their email address.
- 881. By Javier Collado
-
Merged changes to consolidate scripts functionality
Source branch: lp:~nuclearbob/utah/consolidate-scripts
- 882. By Javier Collado
-
Updated version number to upload to PPA
- 886. By Max Brustkern
-
Moved to using explicit package selection
- 887. By Max Brustkern
-
Collapsed vm directory into a single file
- 888. By Max Brustkern
-
Collapsed inventory directory into one file
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Max Brustkern (nuclearbob) wrote : | # |
I changed setup.py to explicitly define the packages used. I also eliminated the utah.provisioni
- 889. By Max Brustkern
-
Removed distribute
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Javier Collado (javier.collado) wrote : | # |
Looks good. Thanks.
I tested the changes and they worked fine using a saucy desktop i386 image. In my test I also removed the utah client deb, since that is no longer needed. I'll take care of that when the changes are merged (once the new release has been created).
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Javier Collado (javier.collado) wrote : | # |
Merged. Thanks for the update in the test cases docstrings by the way.
Preview Diff
1 | === removed file 'distribute-0.6.25-py2.7.egg' |
2 | Binary files distribute-0.6.25-py2.7.egg 2012-06-01 22:04:50 +0000 and distribute-0.6.25-py2.7.egg 1970-01-01 00:00:00 +0000 differ |
3 | === removed file 'distribute-0.6.25.tar.gz' |
4 | Binary files distribute-0.6.25.tar.gz 2012-04-12 15:36:27 +0000 and distribute-0.6.25.tar.gz 1970-01-01 00:00:00 +0000 differ |
5 | === removed file 'distribute_setup.py' |
6 | --- distribute_setup.py 2012-12-05 12:08:46 +0000 |
7 | +++ distribute_setup.py 1970-01-01 00:00:00 +0000 |
8 | @@ -1,485 +0,0 @@ |
9 | -#!python |
10 | -# flake8: noqa |
11 | - |
12 | -""" |
13 | -Bootstrap distribute installation |
14 | - |
15 | -If you want to use setuptools in your package's setup.py, just include this |
16 | -file in the same directory with it, and add this to the top of your setup.py:: |
17 | - |
18 | - from distribute_setup import use_setuptools |
19 | - use_setuptools() |
20 | - |
21 | -If you want to require a specific version of setuptools, set a download |
22 | -mirror, or use an alternate download directory, you can do so by supplying |
23 | -the appropriate options to ``use_setuptools()``. |
24 | - |
25 | -This file can also be run as a script to install or upgrade setuptools. |
26 | -""" |
27 | -import os |
28 | -import sys |
29 | -import time |
30 | -import fnmatch |
31 | -import tempfile |
32 | -import tarfile |
33 | -from distutils import log |
34 | - |
35 | -try: |
36 | - from site import USER_SITE |
37 | -except ImportError: |
38 | - USER_SITE = None |
39 | - |
40 | -try: |
41 | - import subprocess |
42 | - |
43 | - def _python_cmd(*args): |
44 | - args = (sys.executable,) + args |
45 | - return subprocess.call(args) == 0 |
46 | - |
47 | -except ImportError: |
48 | - # will be used for python 2.3 |
49 | - def _python_cmd(*args): |
50 | - args = (sys.executable,) + args |
51 | - # quoting arguments if windows |
52 | - if sys.platform == 'win32': |
53 | - def quote(arg): |
54 | - if ' ' in arg: |
55 | - return '"%s"' % arg |
56 | - return arg |
57 | - args = [quote(arg) for arg in args] |
58 | - return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 |
59 | - |
60 | -DEFAULT_VERSION = "0.6.25" |
61 | -DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" |
62 | -SETUPTOOLS_FAKED_VERSION = "0.6c11" |
63 | - |
64 | -SETUPTOOLS_PKG_INFO = """\ |
65 | -Metadata-Version: 1.0 |
66 | -Name: setuptools |
67 | -Version: %s |
68 | -Summary: xxxx |
69 | -Home-page: xxx |
70 | -Author: xxx |
71 | -Author-email: xxx |
72 | -License: xxx |
73 | -Description: xxx |
74 | -""" % SETUPTOOLS_FAKED_VERSION |
75 | - |
76 | - |
77 | -def _install(tarball, install_args=()): |
78 | - # extracting the tarball |
79 | - tmpdir = tempfile.mkdtemp() |
80 | - log.warn('Extracting in %s', tmpdir) |
81 | - old_wd = os.getcwd() |
82 | - try: |
83 | - os.chdir(tmpdir) |
84 | - tar = tarfile.open(tarball) |
85 | - _extractall(tar) |
86 | - tar.close() |
87 | - |
88 | - # going in the directory |
89 | - subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) |
90 | - os.chdir(subdir) |
91 | - log.warn('Now working in %s', subdir) |
92 | - |
93 | - # installing |
94 | - log.warn('Installing Distribute') |
95 | - if not _python_cmd('setup.py', 'install', *install_args): |
96 | - log.warn('Something went wrong during the installation.') |
97 | - log.warn('See the error message above.') |
98 | - finally: |
99 | - os.chdir(old_wd) |
100 | - |
101 | - |
102 | -def _build_egg(egg, tarball, to_dir): |
103 | - # extracting the tarball |
104 | - tmpdir = tempfile.mkdtemp() |
105 | - log.warn('Extracting in %s', tmpdir) |
106 | - old_wd = os.getcwd() |
107 | - try: |
108 | - os.chdir(tmpdir) |
109 | - tar = tarfile.open(tarball) |
110 | - _extractall(tar) |
111 | - tar.close() |
112 | - |
113 | - # going in the directory |
114 | - subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) |
115 | - os.chdir(subdir) |
116 | - log.warn('Now working in %s', subdir) |
117 | - |
118 | - # building an egg |
119 | - log.warn('Building a Distribute egg in %s', to_dir) |
120 | - _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) |
121 | - |
122 | - finally: |
123 | - os.chdir(old_wd) |
124 | - # returning the result |
125 | - log.warn(egg) |
126 | - if not os.path.exists(egg): |
127 | - raise IOError('Could not build the egg.') |
128 | - |
129 | - |
130 | -def _do_download(version, download_base, to_dir, download_delay): |
131 | - egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' |
132 | - % (version, sys.version_info[0], sys.version_info[1])) |
133 | - if not os.path.exists(egg): |
134 | - tarball = download_setuptools(version, download_base, |
135 | - to_dir, download_delay) |
136 | - _build_egg(egg, tarball, to_dir) |
137 | - sys.path.insert(0, egg) |
138 | - import setuptools |
139 | - setuptools.bootstrap_install_from = egg |
140 | - |
141 | - |
142 | -def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, |
143 | - to_dir=os.curdir, download_delay=15, no_fake=True): |
144 | - # making sure we use the absolute path |
145 | - to_dir = os.path.abspath(to_dir) |
146 | - was_imported = 'pkg_resources' in sys.modules or \ |
147 | - 'setuptools' in sys.modules |
148 | - try: |
149 | - try: |
150 | - import pkg_resources |
151 | - if not hasattr(pkg_resources, '_distribute'): |
152 | - if not no_fake: |
153 | - _fake_setuptools() |
154 | - raise ImportError |
155 | - except ImportError: |
156 | - return _do_download(version, download_base, to_dir, download_delay) |
157 | - try: |
158 | - pkg_resources.require("distribute>="+version) |
159 | - return |
160 | - except pkg_resources.VersionConflict: |
161 | - e = sys.exc_info()[1] |
162 | - if was_imported: |
163 | - sys.stderr.write( |
164 | - "The required version of distribute (>=%s) is not available,\n" |
165 | - "and can't be installed while this script is running. Please\n" |
166 | - "install a more recent version first, using\n" |
167 | - "'easy_install -U distribute'." |
168 | - "\n\n(Currently using %r)\n" % (version, e.args[0])) |
169 | - sys.exit(2) |
170 | - else: |
171 | - del pkg_resources, sys.modules['pkg_resources'] # reload ok |
172 | - return _do_download(version, download_base, to_dir, |
173 | - download_delay) |
174 | - except pkg_resources.DistributionNotFound: |
175 | - return _do_download(version, download_base, to_dir, |
176 | - download_delay) |
177 | - finally: |
178 | - if not no_fake: |
179 | - _create_fake_setuptools_pkg_info(to_dir) |
180 | - |
181 | -def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, |
182 | - to_dir=os.curdir, delay=15): |
183 | - """Download distribute from a specified location and return its filename |
184 | - |
185 | - `version` should be a valid distribute version number that is available |
186 | - as an egg for download under the `download_base` URL (which should end |
187 | - with a '/'). `to_dir` is the directory where the egg will be downloaded. |
188 | - `delay` is the number of seconds to pause before an actual download |
189 | - attempt. |
190 | - """ |
191 | - # making sure we use the absolute path |
192 | - to_dir = os.path.abspath(to_dir) |
193 | - try: |
194 | - from urllib.request import urlopen |
195 | - except ImportError: |
196 | - from urllib2 import urlopen |
197 | - tgz_name = "distribute-%s.tar.gz" % version |
198 | - url = download_base + tgz_name |
199 | - saveto = os.path.join(to_dir, tgz_name) |
200 | - src = dst = None |
201 | - if not os.path.exists(saveto): # Avoid repeated downloads |
202 | - try: |
203 | - log.warn("Downloading %s", url) |
204 | - src = urlopen(url) |
205 | - # Read/write all in one block, so we don't create a corrupt file |
206 | - # if the download is interrupted. |
207 | - data = src.read() |
208 | - dst = open(saveto, "wb") |
209 | - dst.write(data) |
210 | - finally: |
211 | - if src: |
212 | - src.close() |
213 | - if dst: |
214 | - dst.close() |
215 | - return os.path.realpath(saveto) |
216 | - |
217 | -def _no_sandbox(function): |
218 | - def __no_sandbox(*args, **kw): |
219 | - try: |
220 | - from setuptools.sandbox import DirectorySandbox |
221 | - if not hasattr(DirectorySandbox, '_old'): |
222 | - def violation(*args): |
223 | - pass |
224 | - DirectorySandbox._old = DirectorySandbox._violation |
225 | - DirectorySandbox._violation = violation |
226 | - patched = True |
227 | - else: |
228 | - patched = False |
229 | - except ImportError: |
230 | - patched = False |
231 | - |
232 | - try: |
233 | - return function(*args, **kw) |
234 | - finally: |
235 | - if patched: |
236 | - DirectorySandbox._violation = DirectorySandbox._old |
237 | - del DirectorySandbox._old |
238 | - |
239 | - return __no_sandbox |
240 | - |
241 | -def _patch_file(path, content): |
242 | - """Will backup the file then patch it""" |
243 | - existing_content = open(path).read() |
244 | - if existing_content == content: |
245 | - # already patched |
246 | - log.warn('Already patched.') |
247 | - return False |
248 | - log.warn('Patching...') |
249 | - _rename_path(path) |
250 | - with open(path, 'w') as f: |
251 | - f.write(content) |
252 | - return True |
253 | - |
254 | -_patch_file = _no_sandbox(_patch_file) |
255 | - |
256 | -def _same_content(path, content): |
257 | - return open(path).read() == content |
258 | - |
259 | -def _rename_path(path): |
260 | - new_name = path + '.OLD.%s' % time.time() |
261 | - log.warn('Renaming %s into %s', path, new_name) |
262 | - os.rename(path, new_name) |
263 | - return new_name |
264 | - |
265 | -def _remove_flat_installation(placeholder): |
266 | - if not os.path.isdir(placeholder): |
267 | - log.warn('Unkown installation at %s', placeholder) |
268 | - return False |
269 | - found = False |
270 | - for file in os.listdir(placeholder): |
271 | - if fnmatch.fnmatch(file, 'setuptools*.egg-info'): |
272 | - found = True |
273 | - break |
274 | - if not found: |
275 | - log.warn('Could not locate setuptools*.egg-info') |
276 | - return |
277 | - |
278 | - log.warn('Removing elements out of the way...') |
279 | - pkg_info = os.path.join(placeholder, file) |
280 | - if os.path.isdir(pkg_info): |
281 | - patched = _patch_egg_dir(pkg_info) |
282 | - else: |
283 | - patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) |
284 | - |
285 | - if not patched: |
286 | - log.warn('%s already patched.', pkg_info) |
287 | - return False |
288 | - # now let's move the files out of the way |
289 | - for element in ('setuptools', 'pkg_resources.py', 'site.py'): |
290 | - element = os.path.join(placeholder, element) |
291 | - if os.path.exists(element): |
292 | - _rename_path(element) |
293 | - else: |
294 | - log.warn('Could not find the %s element of the ' |
295 | - 'Setuptools distribution', element) |
296 | - return True |
297 | - |
298 | -_remove_flat_installation = _no_sandbox(_remove_flat_installation) |
299 | - |
300 | -def _after_install(dist): |
301 | - log.warn('After install bootstrap.') |
302 | - placeholder = dist.get_command_obj('install').install_purelib |
303 | - _create_fake_setuptools_pkg_info(placeholder) |
304 | - |
305 | -def _create_fake_setuptools_pkg_info(placeholder): |
306 | - if not placeholder or not os.path.exists(placeholder): |
307 | - log.warn('Could not find the install location') |
308 | - return |
309 | - pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) |
310 | - setuptools_file = 'setuptools-%s-py%s.egg-info' % \ |
311 | - (SETUPTOOLS_FAKED_VERSION, pyver) |
312 | - pkg_info = os.path.join(placeholder, setuptools_file) |
313 | - if os.path.exists(pkg_info): |
314 | - log.warn('%s already exists', pkg_info) |
315 | - return |
316 | - |
317 | - log.warn('Creating %s', pkg_info) |
318 | - with open(pkg_info, 'w') as f: |
319 | - f.write(SETUPTOOLS_PKG_INFO) |
320 | - |
321 | - pth_file = os.path.join(placeholder, 'setuptools.pth') |
322 | - log.warn('Creating %s', pth_file) |
323 | - with open(pth_file, 'w') as f: |
324 | - f.write(os.path.join(os.curdir, setuptools_file)) |
325 | - |
326 | -_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info) |
327 | - |
328 | -def _patch_egg_dir(path): |
329 | - # let's check if it's already patched |
330 | - pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') |
331 | - if os.path.exists(pkg_info): |
332 | - if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): |
333 | - log.warn('%s already patched.', pkg_info) |
334 | - return False |
335 | - _rename_path(path) |
336 | - os.mkdir(path) |
337 | - os.mkdir(os.path.join(path, 'EGG-INFO')) |
338 | - pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') |
339 | - with open(pkg_info, 'w') as f: |
340 | - f.write(SETUPTOOLS_PKG_INFO) |
341 | - return True |
342 | - |
343 | -_patch_egg_dir = _no_sandbox(_patch_egg_dir) |
344 | - |
345 | -def _before_install(): |
346 | - log.warn('Before install bootstrap.') |
347 | - _fake_setuptools() |
348 | - |
349 | - |
350 | -def _under_prefix(location): |
351 | - if 'install' not in sys.argv: |
352 | - return True |
353 | - args = sys.argv[sys.argv.index('install')+1:] |
354 | - for index, arg in enumerate(args): |
355 | - for option in ('--root', '--prefix'): |
356 | - if arg.startswith('%s=' % option): |
357 | - top_dir = arg.split('root=')[-1] |
358 | - return location.startswith(top_dir) |
359 | - elif arg == option: |
360 | - if len(args) > index: |
361 | - top_dir = args[index+1] |
362 | - return location.startswith(top_dir) |
363 | - if arg == '--user' and USER_SITE is not None: |
364 | - return location.startswith(USER_SITE) |
365 | - return True |
366 | - |
367 | - |
368 | -def _fake_setuptools(): |
369 | - log.warn('Scanning installed packages') |
370 | - try: |
371 | - import pkg_resources |
372 | - except ImportError: |
373 | - # we're cool |
374 | - log.warn('Setuptools or Distribute does not seem to be installed.') |
375 | - return |
376 | - ws = pkg_resources.working_set |
377 | - try: |
378 | - setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', |
379 | - replacement=False)) |
380 | - except TypeError: |
381 | - # old distribute API |
382 | - setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) |
383 | - |
384 | - if setuptools_dist is None: |
385 | - log.warn('No setuptools distribution found') |
386 | - return |
387 | - # detecting if it was already faked |
388 | - setuptools_location = setuptools_dist.location |
389 | - log.warn('Setuptools installation detected at %s', setuptools_location) |
390 | - |
391 | - # if --root or --preix was provided, and if |
392 | - # setuptools is not located in them, we don't patch it |
393 | - if not _under_prefix(setuptools_location): |
394 | - log.warn('Not patching, --root or --prefix is installing Distribute' |
395 | - ' in another location') |
396 | - return |
397 | - |
398 | - # let's see if its an egg |
399 | - if not setuptools_location.endswith('.egg'): |
400 | - log.warn('Non-egg installation') |
401 | - res = _remove_flat_installation(setuptools_location) |
402 | - if not res: |
403 | - return |
404 | - else: |
405 | - log.warn('Egg installation') |
406 | - pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') |
407 | - if (os.path.exists(pkg_info) and |
408 | - _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): |
409 | - log.warn('Already patched.') |
410 | - return |
411 | - log.warn('Patching...') |
412 | - # let's create a fake egg replacing setuptools one |
413 | - res = _patch_egg_dir(setuptools_location) |
414 | - if not res: |
415 | - return |
416 | - log.warn('Patched done.') |
417 | - _relaunch() |
418 | - |
419 | - |
420 | -def _relaunch(): |
421 | - log.warn('Relaunching...') |
422 | - # we have to relaunch the process |
423 | - # pip marker to avoid a relaunch bug |
424 | - if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']: |
425 | - sys.argv[0] = 'setup.py' |
426 | - args = [sys.executable] + sys.argv |
427 | - sys.exit(subprocess.call(args)) |
428 | - |
429 | - |
430 | -def _extractall(self, path=".", members=None): |
431 | - """Extract all members from the archive to the current working |
432 | - directory and set owner, modification time and permissions on |
433 | - directories afterwards. `path' specifies a different directory |
434 | - to extract to. `members' is optional and must be a subset of the |
435 | - list returned by getmembers(). |
436 | - """ |
437 | - import copy |
438 | - import operator |
439 | - from tarfile import ExtractError |
440 | - directories = [] |
441 | - |
442 | - if members is None: |
443 | - members = self |
444 | - |
445 | - for tarinfo in members: |
446 | - if tarinfo.isdir(): |
447 | - # Extract directories with a safe mode. |
448 | - directories.append(tarinfo) |
449 | - tarinfo = copy.copy(tarinfo) |
450 | - tarinfo.mode = 448 # decimal for oct 0700 |
451 | - self.extract(tarinfo, path) |
452 | - |
453 | - # Reverse sort directories. |
454 | - if sys.version_info < (2, 4): |
455 | - def sorter(dir1, dir2): |
456 | - return cmp(dir1.name, dir2.name) |
457 | - directories.sort(sorter) |
458 | - directories.reverse() |
459 | - else: |
460 | - directories.sort(key=operator.attrgetter('name'), reverse=True) |
461 | - |
462 | - # Set correct owner, mtime and filemode on directories. |
463 | - for tarinfo in directories: |
464 | - dirpath = os.path.join(path, tarinfo.name) |
465 | - try: |
466 | - self.chown(tarinfo, dirpath) |
467 | - self.utime(tarinfo, dirpath) |
468 | - self.chmod(tarinfo, dirpath) |
469 | - except ExtractError: |
470 | - e = sys.exc_info()[1] |
471 | - if self.errorlevel > 1: |
472 | - raise |
473 | - else: |
474 | - self._dbg(1, "tarfile: %s" % e) |
475 | - |
476 | -def _build_install_args(argv): |
477 | - install_args = [] |
478 | - user_install = '--user' in argv |
479 | - if user_install and sys.version_info < (2,6): |
480 | - log.warn("--user requires Python 2.6 or later") |
481 | - raise SystemExit(1) |
482 | - if user_install: |
483 | - install_args.append('--user') |
484 | - return install_args |
485 | - |
486 | -def main(argv, version=DEFAULT_VERSION): |
487 | - """Install or upgrade setuptools and EasyInstall""" |
488 | - tarball = download_setuptools() |
489 | - _install(tarball, _build_install_args(argv)) |
490 | - |
491 | - |
492 | -if __name__ == '__main__': |
493 | - main(sys.argv[1:]) |
494 | |
495 | === modified file 'docs/source/reference.rst' |
496 | --- docs/source/reference.rst 2013-04-24 10:32:29 +0000 |
497 | +++ docs/source/reference.rst 2013-05-02 18:27:25 +0000 |
498 | @@ -106,6 +106,9 @@ |
499 | .. automodule:: utah.provisioning.exceptions |
500 | :members: |
501 | |
502 | +.. automodule:: utah.provisioning.inventory |
503 | + :members: |
504 | + |
505 | .. automodule:: utah.provisioning.provisioning |
506 | :members: |
507 | |
508 | @@ -115,6 +118,9 @@ |
509 | .. automodule:: utah.provisioning.ssh |
510 | :members: |
511 | |
512 | +.. automodule:: utah.provisioning.vm |
513 | + :members: |
514 | + |
515 | ``utah.provisioning.baremetal`` |
516 | ------------------------------- |
517 | |
518 | @@ -131,29 +137,3 @@ |
519 | |
520 | .. automodule:: utah.provisioning.baremetal.exceptions |
521 | :members: |
522 | - |
523 | -``utah.provisioning.inventory`` |
524 | -------------------------------- |
525 | - |
526 | -.. automodule:: utah.provisioning.inventory |
527 | - |
528 | -.. automodule:: utah.provisioning.inventory.exceptions |
529 | - :members: |
530 | - |
531 | -.. automodule:: utah.provisioning.inventory.inventory |
532 | - :members: |
533 | - |
534 | -.. automodule:: utah.provisioning.inventory.sqlite |
535 | - :members: |
536 | - |
537 | -``utah.provisioning.vm`` |
538 | -------------------------- |
539 | - |
540 | -.. automodule:: utah.provisioning.vm |
541 | - |
542 | -.. automodule:: utah.provisioning.vm.exceptions |
543 | - :members: |
544 | - |
545 | -.. automodule:: utah.provisioning.vm.vm |
546 | - :members: |
547 | - |
548 | |
549 | === modified file 'examples/run_utah_tests.py' |
550 | --- examples/run_utah_tests.py 2013-05-01 18:04:36 +0000 |
551 | +++ examples/run_utah_tests.py 2013-05-02 18:27:25 +0000 |
552 | @@ -36,7 +36,7 @@ |
553 | from utah.provisioning.baremetal.inventory import \ |
554 | ManualBaremetalSQLiteInventory |
555 | from utah.provisioning.ssh import ProvisionedMachine |
556 | -from utah.provisioning.vm.vm import TinySQLiteInventory |
557 | +from utah.provisioning.vm import TinySQLiteInventory |
558 | from utah.run import ( |
559 | configure_logging, |
560 | master_runlist_argument, |
561 | |
562 | === modified file 'setup.py' |
563 | --- setup.py 2013-04-10 20:13:44 +0000 |
564 | +++ setup.py 2013-05-02 18:27:25 +0000 |
565 | @@ -18,13 +18,12 @@ |
566 | """Provide installation information for setuptools.""" |
567 | |
568 | |
569 | -import distribute_setup |
570 | -distribute_setup.use_setuptools() |
571 | -from setuptools import setup, find_packages |
572 | - |
573 | import os |
574 | import re |
575 | |
576 | +from setuptools import setup |
577 | + |
578 | + |
579 | # look/set what version we have |
580 | version = "0.0" |
581 | changelog = "debian/changelog" |
582 | @@ -48,7 +47,10 @@ |
583 | setup( |
584 | name='utah', |
585 | version=version, |
586 | - packages=find_packages(), |
587 | + packages=['utah', |
588 | + 'utah.client', |
589 | + 'utah.provisioning', |
590 | + 'utah.provisioning.baremetal'], |
591 | maintainer=maintainer, |
592 | maintainer_email=maintainer_email, |
593 | ) |
594 | |
595 | === added file 'tests/__init__.py' |
596 | --- tests/__init__.py 1970-01-01 00:00:00 +0000 |
597 | +++ tests/__init__.py 2013-05-02 18:27:25 +0000 |
598 | @@ -0,0 +1,16 @@ |
599 | +# Ubuntu Testing Automation Harness |
600 | +# Copyright 2012 Canonical Ltd. |
601 | + |
602 | +# This program is free software: you can redistribute it and/or modify it |
603 | +# under the terms of the GNU General Public License version 3, as published |
604 | +# by the Free Software Foundation. |
605 | + |
606 | +# This program is distributed in the hope that it will be useful, but |
607 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
608 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
609 | +# PURPOSE. See the GNU General Public License for more details. |
610 | + |
611 | +# You should have received a copy of the GNU General Public License along |
612 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
613 | + |
614 | +"""server self tests""" |
615 | |
616 | === modified file 'tests/test_rsyslog.py' |
617 | --- tests/test_rsyslog.py 2013-04-24 11:37:21 +0000 |
618 | +++ tests/test_rsyslog.py 2013-05-02 18:27:25 +0000 |
619 | @@ -253,7 +253,7 @@ |
620 | self.usefile(True) |
621 | |
622 | def test_timeout(self): |
623 | - """UTAHTimeout is raised on timeout""" |
624 | + """Verify UTAHTimeout is raised on timeout.""" |
625 | steps = [ |
626 | { |
627 | "message": "message_1", |
628 | |
629 | === modified file 'utah/client/common.py' |
630 | --- utah/client/common.py 2013-04-25 14:12:49 +0000 |
631 | +++ utah/client/common.py 2013-05-02 18:27:25 +0000 |
632 | @@ -115,7 +115,7 @@ |
633 | |
634 | # Process queue stuff inspired by: |
635 | # http://stackoverflow.com/a/4896288 |
636 | -def enqueue_output(out, queue): |
637 | +def _enqueue_output(out, queue): |
638 | for line in iter(out.readline, b''): |
639 | queue.put(line) |
640 | out.close() |
641 | @@ -195,10 +195,10 @@ |
642 | signal.signal(signal.SIGALRM, alarm_handler) |
643 | signal.alarm(timeout) |
644 | |
645 | - outt = Thread(target=enqueue_output, args=(p.stdout, outq)) |
646 | + outt = Thread(target=_enqueue_output, args=(p.stdout, outq)) |
647 | outt.daemon = True |
648 | outt.start() |
649 | - errt = Thread(target=enqueue_output, args=(p.stderr, errq)) |
650 | + errt = Thread(target=_enqueue_output, args=(p.stderr, errq)) |
651 | errt.daemon = True |
652 | errt.start() |
653 | |
654 | @@ -416,6 +416,7 @@ |
655 | |
656 | @classmethod |
657 | def check_schema(self, schema): |
658 | + """Call the superclass directly since super doesn't work here.""" |
659 | jsonschema.Draft4Validator.check_schema(schema) |
660 | |
661 | def validate_properties(self, properties, instance, schema): |
662 | |
663 | === modified file 'utah/client/tests/test_runner.py' |
664 | --- utah/client/tests/test_runner.py 2013-05-01 17:37:58 +0000 |
665 | +++ utah/client/tests/test_runner.py 2013-05-02 18:27:25 +0000 |
666 | @@ -49,7 +49,7 @@ |
667 | self.result_class = ResultYAML |
668 | self.state_file = '/tmp/state.yaml' |
669 | self.state_agent = StateAgentYAML(state_file=self.state_file) |
670 | - self.output_file='/tmp/utah.out' |
671 | + self.output_file = '/tmp/utah.out' |
672 | self.runner = Runner(install_type='desktop', |
673 | result_class=self.result_class, |
674 | state_agent=self.state_agent, |
675 | @@ -202,27 +202,36 @@ |
676 | |
677 | |
678 | class TestRunnerMasterRunlistSchema(unittest.TestCase): |
679 | - """Master runlist schema test cases.""" |
680 | + |
681 | + """Provide master runlist schema test cases.""" |
682 | + |
683 | def setUp(self): |
684 | + """Setup needed resources.""" |
685 | schema = Runner.MASTER_RUNLIST_SCHEMA |
686 | DefaultValidator.check_schema(schema) |
687 | self.validator = DefaultValidator(schema) |
688 | |
689 | def validate(self, data): |
690 | + """Validate a schema. |
691 | + |
692 | + :returns: validates schema |
693 | + :rtype: object |
694 | + |
695 | + """ |
696 | return self.validator.validate(data) |
697 | |
698 | def test_empty_string_invalid(self): |
699 | - """An empty string doesn't validate.""" |
700 | + """Verify an empty string doesn't validate.""" |
701 | with self.assertRaises(jsonschema.ValidationError): |
702 | self.validate('') |
703 | |
704 | def test_empty_dict_invalid(self): |
705 | - """An empty dictionary is invalid.""" |
706 | + """Verify an empty dictionary is invalid.""" |
707 | with self.assertRaises(jsonschema.ValidationError): |
708 | self.validate({}) |
709 | |
710 | def test_valid(self): |
711 | - """An example of valid data.""" |
712 | + """Verify valid data works.""" |
713 | self.validate({ |
714 | 'testsuites': [{ |
715 | 'name': 'name', |
716 | @@ -232,21 +241,21 @@ |
717 | }) |
718 | |
719 | def test_testsuites_required(self): |
720 | - """A list of test suites is required.""" |
721 | + """Verify a list of test suites is required.""" |
722 | with self.assertRaises(jsonschema.ValidationError): |
723 | self.validate({ |
724 | 'battery_measurements': True, |
725 | }) |
726 | |
727 | def test_testsuites_empty_invalid(self): |
728 | - """An empty list of test suites is invalid.""" |
729 | + """Verify an empty list of test suites is invalid.""" |
730 | with self.assertRaises(jsonschema.ValidationError): |
731 | self.validate({ |
732 | 'testsuites': [], |
733 | }) |
734 | |
735 | def test_testsuite_name_required(self): |
736 | - """Test suite name is required.""" |
737 | + """Verify test suite name is required.""" |
738 | with self.assertRaises(jsonschema.ValidationError): |
739 | self.validate({ |
740 | 'testsuites': [{ |
741 | @@ -256,7 +265,7 @@ |
742 | }) |
743 | |
744 | def test_testsuite_fetch_method_required(self): |
745 | - """Test suite fetch method is required.""" |
746 | + """Verify test suite fetch method is required.""" |
747 | with self.assertRaises(jsonschema.ValidationError): |
748 | self.validate({ |
749 | 'testsuites': [{ |
750 | @@ -266,7 +275,7 @@ |
751 | }) |
752 | |
753 | def test_testsuite_fetch_method_known_values(self): |
754 | - """Test suite fetch method known values are valid.""" |
755 | + """Verify test suite fetch method known values are valid.""" |
756 | testsuite = { |
757 | 'name': 'name', |
758 | 'fetch_location': 'fetch location', |
759 | @@ -279,7 +288,7 @@ |
760 | self.validate(data) |
761 | |
762 | def test_testsuite_fetch_method_unknown_value(self): |
763 | - """Test suite fetch method unknown values are valid.""" |
764 | + """Verify test suite fetch method unknown values are valid.""" |
765 | with self.assertRaises(jsonschema.ValidationError): |
766 | self.validate({ |
767 | 'testsuites': [{ |
768 | @@ -290,7 +299,7 @@ |
769 | }) |
770 | |
771 | def test_testsuite_fetch_location_required(self): |
772 | - """Test suite fetch location is required.""" |
773 | + """Verify test suite fetch location is required.""" |
774 | with self.assertRaises(jsonschema.ValidationError): |
775 | self.validate({ |
776 | 'testsuites': [{ |
777 | @@ -300,7 +309,7 @@ |
778 | }) |
779 | |
780 | def test_testsuite_include_tests_empty_invalid(self): |
781 | - """Empty list of included tests is invalid.""" |
782 | + """Verify an empty list of included tests is invalid.""" |
783 | with self.assertRaises(jsonschema.ValidationError): |
784 | self.validate({ |
785 | 'testsuites': [{ |
786 | @@ -312,7 +321,7 @@ |
787 | }) |
788 | |
789 | def test_testsuite_include_tests_string(self): |
790 | - """List of strings as included tests is valid.""" |
791 | + """Verify a list of strings as included tests is valid.""" |
792 | self.validate({ |
793 | 'testsuites': [{ |
794 | 'name': 'name', |
795 | @@ -323,7 +332,7 @@ |
796 | }) |
797 | |
798 | def test_testsuite_exclude_tests_empty_invalid(self): |
799 | - """Empty list of excluded tests is invalid.""" |
800 | + """Verify an empty list of excluded tests is invalid.""" |
801 | with self.assertRaises(jsonschema.ValidationError): |
802 | self.validate({ |
803 | 'testsuites': [{ |
804 | @@ -335,7 +344,7 @@ |
805 | }) |
806 | |
807 | def test_testsuite_exclude_tests_string(self): |
808 | - """List of strings as excluded tests is valid.""" |
809 | + """Verify a list of strings as excluded tests is valid.""" |
810 | self.validate({ |
811 | 'testsuites': [{ |
812 | 'name': 'name', |
813 | @@ -346,7 +355,7 @@ |
814 | }) |
815 | |
816 | def test_battery_measurements_false_by_default(self): |
817 | - """Battery measurements is false by default""" |
818 | + """Verify battery measurements is false by default.""" |
819 | data = { |
820 | 'testsuites': [{ |
821 | 'name': 'name', |
822 | @@ -358,7 +367,7 @@ |
823 | self.assertFalse(data['battery_measurements']) |
824 | |
825 | def test_battery_measurements_string_invalid(self): |
826 | - """A battery measurements string value is invalid""" |
827 | + """Verify battery measurements string value is invalid.""" |
828 | with self.assertRaises(jsonschema.ValidationError): |
829 | self.validate({ |
830 | 'testsuites': [{ |
831 | @@ -370,7 +379,7 @@ |
832 | }) |
833 | |
834 | def test_battery_measurements_boolean_valid(self): |
835 | - """A battery measurements boolean value is valid""" |
836 | + """Verify a battery measurements boolean value is valid.""" |
837 | self.validate({ |
838 | 'testsuites': [{ |
839 | 'name': 'name', |
840 | @@ -381,7 +390,7 @@ |
841 | }) |
842 | |
843 | def test_zero_timeout_invalid(self): |
844 | - """A zero timeout is invalid""" |
845 | + """Verify a zero timeout is invalid.""" |
846 | with self.assertRaises(jsonschema.ValidationError): |
847 | self.validate({ |
848 | 'testsuites': [{ |
849 | @@ -393,7 +402,7 @@ |
850 | }) |
851 | |
852 | def test_negative_timeout_invalid(self): |
853 | - """A negative timeout is invalid""" |
854 | + """Verify a negative timeout is invalid.""" |
855 | with self.assertRaises(jsonschema.ValidationError): |
856 | self.validate({ |
857 | 'testsuites': [{ |
858 | @@ -405,7 +414,7 @@ |
859 | }) |
860 | |
861 | def test_repeat_count_zero_by_default(self): |
862 | - """Repeat count is zero by default""" |
863 | + """Verify repeat count is zero by default.""" |
864 | data = { |
865 | 'testsuites': [{ |
866 | 'name': 'name', |
867 | @@ -418,7 +427,7 @@ |
868 | self.assertEqual(data['repeat_count'], 0) |
869 | |
870 | def test_negative_repeat_count_invalid(self): |
871 | - """A negative repeat count is invalid""" |
872 | + """Verift. negative repeat count is invalid.""" |
873 | with self.assertRaises(jsonschema.ValidationError): |
874 | self.validate({ |
875 | 'testsuites': [{ |
876 | |
877 | === modified file 'utah/client/tests/test_testcase.py' |
878 | --- utah/client/tests/test_testcase.py 2013-04-29 21:04:46 +0000 |
879 | +++ utah/client/tests/test_testcase.py 2013-05-02 18:27:25 +0000 |
880 | @@ -143,13 +143,22 @@ |
881 | |
882 | |
883 | class TestTestCaseControlSchema(unittest.TestCase): |
884 | + |
885 | """Test case control schema test cases.""" |
886 | - def setUp(self,): |
887 | + |
888 | + def setUp(self): |
889 | + """Setup needed resources.""" |
890 | schema = testcase.TestCase.CONTROL_SCHEMA |
891 | DefaultValidator.check_schema(schema) |
892 | self.validator = DefaultValidator(schema) |
893 | |
894 | def validate(self, data): |
895 | + """Validate a schema. |
896 | + |
897 | + :returns: validates schema |
898 | + :rtype: object |
899 | + |
900 | + """ |
901 | schema = testcase.TestCase.CONTROL_SCHEMA |
902 | return jsonschema.validate(data, schema) |
903 | |
904 | @@ -164,7 +173,7 @@ |
905 | self.validate({}) |
906 | |
907 | def test_valid(self): |
908 | - """An example of valid data.""" |
909 | + """Verify valid data works.""" |
910 | self.validate({ |
911 | 'description': 'description', |
912 | 'dependencies': 'dependencies', |
913 | @@ -175,7 +184,7 @@ |
914 | }) |
915 | |
916 | def test_description_required(self): |
917 | - """Description is a required property.""" |
918 | + """Verify description is a required property.""" |
919 | with self.assertRaises(jsonschema.ValidationError): |
920 | self.validate({ |
921 | 'dependencies': 'dependencies', |
922 | @@ -186,7 +195,7 @@ |
923 | }) |
924 | |
925 | def test_dependencies_required(self): |
926 | - """Dependencies is a required property.""" |
927 | + """Verify dependencies is a required property.""" |
928 | with self.assertRaises(jsonschema.ValidationError): |
929 | self.validate({ |
930 | 'description': 'description', |
931 | @@ -197,7 +206,7 @@ |
932 | }) |
933 | |
934 | def test_action_required(self): |
935 | - """Action is a required property.""" |
936 | + """Verify action is a required property.""" |
937 | with self.assertRaises(jsonschema.ValidationError): |
938 | self.validate({ |
939 | 'description': 'description', |
940 | @@ -208,7 +217,7 @@ |
941 | }) |
942 | |
943 | def test_expected_results_required(self): |
944 | - """Expected results is a required property.""" |
945 | + """Verify expected results is a required property.""" |
946 | with self.assertRaises(jsonschema.ValidationError): |
947 | self.validate({ |
948 | 'description': 'description', |
949 | @@ -219,7 +228,7 @@ |
950 | }) |
951 | |
952 | def test_command_required(self): |
953 | - """Command is a required property.""" |
954 | + """Verify command is a required property.""" |
955 | with self.assertRaises(jsonschema.ValidationError): |
956 | self.validate({ |
957 | 'description': 'description', |
958 | @@ -230,7 +239,7 @@ |
959 | }) |
960 | |
961 | def test_zero_timeout_invalid(self): |
962 | - """A zero timeout is invalid""" |
963 | + """Verify a zero timeout is invalid.""" |
964 | with self.assertRaises(jsonschema.ValidationError): |
965 | self.validate({ |
966 | 'description': 'description', |
967 | @@ -243,7 +252,7 @@ |
968 | }) |
969 | |
970 | def test_negative_timeout_invalid(self): |
971 | - """A negative timeout is invalid""" |
972 | + """Verify a negative timeout is invalid.""" |
973 | with self.assertRaises(jsonschema.ValidationError): |
974 | self.validate({ |
975 | 'description': 'description', |
976 | @@ -256,7 +265,7 @@ |
977 | }) |
978 | |
979 | def test_type_userland_valid(self): |
980 | - """Userland type is valid.""" |
981 | + """Verify userland type is valid.""" |
982 | self.validate({ |
983 | 'description': 'description', |
984 | 'dependencies': 'dependencies', |
985 | @@ -268,7 +277,7 @@ |
986 | }) |
987 | |
988 | def test_type_unknown_invalid(self): |
989 | - """Unknown type is valid.""" |
990 | + """Verify unknown type is valid.""" |
991 | with self.assertRaises(jsonschema.ValidationError): |
992 | self.validate({ |
993 | 'description': 'description', |
994 | @@ -281,7 +290,7 @@ |
995 | }) |
996 | |
997 | def test_reboot_known_valid(self): |
998 | - """Reboot known values are valid.""" |
999 | + """Verify reboot known values are valid.""" |
1000 | data = { |
1001 | 'description': 'description', |
1002 | 'dependencies': 'dependencies', |
1003 | @@ -296,7 +305,7 @@ |
1004 | self.validate(data) |
1005 | |
1006 | def test_unknown_reboot_invalid(self): |
1007 | - """Reboot unknown value is invalid.""" |
1008 | + """Verify reboot unknown value is invalid.""" |
1009 | with self.assertRaises(jsonschema.ValidationError): |
1010 | self.validate({ |
1011 | 'description': 'description', |
1012 | |
1013 | === modified file 'utah/client/tests/test_testsuite.py' |
1014 | --- utah/client/tests/test_testsuite.py 2013-04-25 14:14:19 +0000 |
1015 | +++ utah/client/tests/test_testsuite.py 2013-05-02 18:27:25 +0000 |
1016 | @@ -163,43 +163,51 @@ |
1017 | |
1018 | |
1019 | class TestTestSuiteRunlistSchema(unittest.TestCase): |
1020 | + |
1021 | """Test suite run list schema test cases.""" |
1022 | |
1023 | def setUp(self): |
1024 | + """Initialize basic test case data.""" |
1025 | schema = testsuite.TestSuite.RUNLIST_SCHEMA |
1026 | DefaultValidator.check_schema(schema) |
1027 | self.validator = DefaultValidator(schema) |
1028 | |
1029 | def validate(self, data): |
1030 | + """Validate a schema. |
1031 | + |
1032 | + :returns: validates schema |
1033 | + :rtype: object |
1034 | + |
1035 | + """ |
1036 | return self.validator.validate(data) |
1037 | |
1038 | def test_empty_string_invalid(self): |
1039 | - """An empty string doesn't validate.""" |
1040 | + """Verify an empty string doesn't validate.""" |
1041 | with self.assertRaises(jsonschema.ValidationError): |
1042 | self.validate('') |
1043 | |
1044 | def test_empty_dict_invalid(self): |
1045 | - """An empty dictionary doesn't validate.""" |
1046 | + """Verify an empty dictionary doesn't validate.""" |
1047 | with self.assertRaises(jsonschema.ValidationError): |
1048 | self.validate({}) |
1049 | |
1050 | def test_empty_list_invalid(self): |
1051 | - """An empty list doesn't validate.""" |
1052 | + """Verify an empty list doesn't validate.""" |
1053 | with self.assertRaises(jsonschema.ValidationError): |
1054 | self.validate([]) |
1055 | |
1056 | def test_string_list_invalid(self): |
1057 | - """A list of strings is invalid.""" |
1058 | + """Verify a list of strings is invalid.""" |
1059 | with self.assertRaises(jsonschema.ValidationError): |
1060 | self.validate(['a', 'b', 'c']) |
1061 | |
1062 | def test_empty_dict_list_invalid(self): |
1063 | - """A list of empty dictionaries is invalid.""" |
1064 | + """Verify a list of empty dictionaries is invalid.""" |
1065 | with self.assertRaises(jsonschema.ValidationError): |
1066 | self.validate([{}, {}, {}]) |
1067 | |
1068 | def test_unknown_test_property_invalid(self): |
1069 | - """An unknown property in a test object invalid.""" |
1070 | + """Verify an unknown property in a test object invalid.""" |
1071 | with self.assertRaises(jsonschema.ValidationError): |
1072 | self.validate( |
1073 | [{'test': 'test name', |
1074 | @@ -207,13 +215,13 @@ |
1075 | }]) |
1076 | |
1077 | def test_empty_overrides_invalid(self): |
1078 | - """An empty overrides section is invalid.""" |
1079 | + """Verify an empty overrides section is invalid.""" |
1080 | with self.assertRaises(jsonschema.ValidationError): |
1081 | self.validate([{'test': 'test name', |
1082 | 'overrides': {}}]) |
1083 | |
1084 | def test_unknown_property_in_overrides_invalid(self): |
1085 | - """An unknown property in overrides section is invalid.""" |
1086 | + """Verify an unknown property in overrides section is invalid.""" |
1087 | with self.assertRaises(jsonschema.ValidationError): |
1088 | self.validate( |
1089 | [{'test': 'test name', |
1090 | @@ -221,25 +229,25 @@ |
1091 | }]) |
1092 | |
1093 | def test_zero_timeout_invalid(self): |
1094 | - """A zero timeout is invalid""" |
1095 | + """Verify a zero timeout is invalid.""" |
1096 | with self.assertRaises(jsonschema.ValidationError): |
1097 | self.validate([{'test': 'test name', |
1098 | 'overrides': {'timeout': 0}}]) |
1099 | |
1100 | def test_negative_timeout_invalid(self): |
1101 | - """A negative timeout is invalid""" |
1102 | + """Verify a negative timeout is invalid.""" |
1103 | with self.assertRaises(jsonschema.ValidationError): |
1104 | self.validate([{'test': 'test name', |
1105 | 'overrides': {'timeout': -1}}]) |
1106 | |
1107 | def test_list_valid(self): |
1108 | - """A list of test cases is valid.""" |
1109 | + """Verify a list of test cases is valid.""" |
1110 | self.validate( |
1111 | [{'test': 'test name'}, |
1112 | {'test': 'test name 2'}]) |
1113 | |
1114 | def test_with_overrides_list_valid(self): |
1115 | - """A list of test case names with overrides is valid.""" |
1116 | + """Verify a list of test case names with overrides is valid.""" |
1117 | self.validate([ |
1118 | {'test': 'test name', |
1119 | 'overrides': {'timeout': 1}, |
1120 | @@ -251,13 +259,22 @@ |
1121 | |
1122 | |
1123 | class TestTestSuiteControlSchema(unittest.TestCase): |
1124 | + |
1125 | """Test suite control schema test cases.""" |
1126 | + |
1127 | def setUp(self): |
1128 | + """Initialize basic test case data.""" |
1129 | schema = testsuite.TestSuite.CONTROL_SCHEMA |
1130 | DefaultValidator.check_schema(schema) |
1131 | self.validator = DefaultValidator(schema) |
1132 | |
1133 | def validate(self, data): |
1134 | + """Validate a schema. |
1135 | + |
1136 | + :returns: validates schema |
1137 | + :rtype: object |
1138 | + |
1139 | + """ |
1140 | return self.validator.validate(data) |
1141 | |
1142 | def test_empty_string_invalid(self): |
1143 | |
1144 | === modified file 'utah/client/tests/test_vcs_git.py' |
1145 | --- utah/client/tests/test_vcs_git.py 2013-04-05 19:32:58 +0000 |
1146 | +++ utah/client/tests/test_vcs_git.py 2013-05-02 18:27:25 +0000 |
1147 | @@ -33,6 +33,7 @@ |
1148 | os.mkdir(GIT_TEST_REPO) |
1149 | |
1150 | run_cmd("git init", cwd=GIT_TEST_REPO) |
1151 | + run_cmd('git config user.email "utah@launchpad.net"', cwd=GIT_TEST_REPO) |
1152 | run_cmd("touch test.py", cwd=GIT_TEST_REPO) |
1153 | run_cmd("git add test.py", cwd=GIT_TEST_REPO) |
1154 | run_cmd("git commit -m'Initial import' test.py", cwd=GIT_TEST_REPO) |
1155 | |
1156 | === modified file 'utah/provisioning/baremetal/inventory.py' |
1157 | --- utah/provisioning/baremetal/inventory.py 2013-04-10 15:42:26 +0000 |
1158 | +++ utah/provisioning/baremetal/inventory.py 2013-05-02 18:27:25 +0000 |
1159 | @@ -21,9 +21,10 @@ |
1160 | import os |
1161 | |
1162 | from utah.process import pid_in_use |
1163 | -from utah.provisioning.inventory.exceptions import \ |
1164 | - UTAHProvisioningInventoryException |
1165 | -from utah.provisioning.inventory.sqlite import SQLiteInventory |
1166 | +from utah.provisioning.inventory import ( |
1167 | + UTAHProvisioningInventoryException, |
1168 | + SQLiteInventory, |
1169 | +) |
1170 | |
1171 | |
1172 | class ManualBaremetalSQLiteInventory(SQLiteInventory): |
1173 | |
1174 | === removed directory 'utah/provisioning/inventory' |
1175 | === renamed file 'utah/provisioning/inventory/inventory.py' => 'utah/provisioning/inventory.py' |
1176 | --- utah/provisioning/inventory/inventory.py 2013-04-04 15:39:49 +0000 |
1177 | +++ utah/provisioning/inventory.py 2013-05-02 18:27:25 +0000 |
1178 | @@ -16,9 +16,19 @@ |
1179 | """Provide basic inventory routines.""" |
1180 | |
1181 | |
1182 | +import logging |
1183 | import os |
1184 | -from utah.provisioning.inventory.exceptions import \ |
1185 | - UTAHProvisioningInventoryException |
1186 | +import sqlite3 |
1187 | + |
1188 | +from utah import config |
1189 | +from utah.provisioning.exceptions import UTAHProvisioningException |
1190 | + |
1191 | + |
1192 | +class UTAHProvisioningInventoryException(UTAHProvisioningException): |
1193 | + |
1194 | + """Provide a class for UTAH provisioning inventory exceptions.""" |
1195 | + |
1196 | + pass |
1197 | |
1198 | |
1199 | class Inventory(object): |
1200 | @@ -107,3 +117,49 @@ |
1201 | |
1202 | """ |
1203 | return False |
1204 | + |
1205 | + |
1206 | +class SQLiteInventory(Inventory): |
1207 | + |
1208 | + """Provide basic SQLite database access with a cursor.""" |
1209 | + |
1210 | + def __init__(self, db='~/.utah-sqlite-inventory', *args, **kw): |
1211 | + db = os.path.expanduser(db) |
1212 | + super(SQLiteInventory, self).__init__(*args, uniqueid=db, **kw) |
1213 | + self.db = db |
1214 | + self._connection = sqlite3.connect( |
1215 | + self.db, config.sqlite3_db_connection_timeout) |
1216 | + self._connection.isolation_level = None |
1217 | + self._connection.row_factory = sqlite3.Row |
1218 | + |
1219 | + def execute(self, sql, parameters=None): |
1220 | + """Execute SQL statement and return cursor. |
1221 | + |
1222 | + This method is expected to be used as a wrapper around all |
1223 | + `connection.execute` calls so that all the SQL statements are logged in |
1224 | + case this information is needed to troubleshoot problems. |
1225 | + |
1226 | + :param sql: A sql statement to be executed |
1227 | + :type sql: str |
1228 | + :param parameters: |
1229 | + Parameters to use to replace the placeholder |
1230 | + values in the sql statement. |
1231 | + :type parameters: |
1232 | + list (question mark placeholders) | |
1233 | + dict (colon named placeholders) |
1234 | + :returns: Cursor used to execute statement |
1235 | + :rtype: object |
1236 | + |
1237 | + """ |
1238 | + if parameters is None: |
1239 | + parameters = [] |
1240 | + |
1241 | + logging.debug('Executing SQL statement: {}, {}' |
1242 | + .format(sql, parameters)) |
1243 | + cursor = self._connection.execute(sql, parameters) |
1244 | + return cursor |
1245 | + |
1246 | + def delete(self): |
1247 | + """Remove database.""" |
1248 | + os.unlink(self.db) |
1249 | + super(SQLiteInventory, self).delete() |
1250 | |
1251 | === removed file 'utah/provisioning/inventory/__init__.py' |
1252 | --- utah/provisioning/inventory/__init__.py 2013-04-04 13:42:40 +0000 |
1253 | +++ utah/provisioning/inventory/__init__.py 1970-01-01 00:00:00 +0000 |
1254 | @@ -1,16 +0,0 @@ |
1255 | -# Ubuntu Testing Automation Harness |
1256 | -# Copyright 2012 Canonical Ltd. |
1257 | - |
1258 | -# This program is free software: you can redistribute it and/or modify it |
1259 | -# under the terms of the GNU General Public License version 3, as published |
1260 | -# by the Free Software Foundation. |
1261 | - |
1262 | -# This program is distributed in the hope that it will be useful, but |
1263 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
1264 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1265 | -# PURPOSE. See the GNU General Public License for more details. |
1266 | - |
1267 | -# You should have received a copy of the GNU General Public License along |
1268 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
1269 | - |
1270 | -"""utah.provisioning.inventory""" |
1271 | |
1272 | === removed file 'utah/provisioning/inventory/exceptions.py' |
1273 | --- utah/provisioning/inventory/exceptions.py 2013-04-03 18:33:32 +0000 |
1274 | +++ utah/provisioning/inventory/exceptions.py 1970-01-01 00:00:00 +0000 |
1275 | @@ -1,26 +0,0 @@ |
1276 | -# Ubuntu Testing Automation Harness |
1277 | -# Copyright 2012 Canonical Ltd. |
1278 | - |
1279 | -# This program is free software: you can redistribute it and/or modify it |
1280 | -# under the terms of the GNU General Public License version 3, as published |
1281 | -# by the Free Software Foundation. |
1282 | - |
1283 | -# This program is distributed in the hope that it will be useful, but |
1284 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
1285 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1286 | -# PURPOSE. See the GNU General Public License for more details. |
1287 | - |
1288 | -# You should have received a copy of the GNU General Public License along |
1289 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
1290 | - |
1291 | -"""Provide exceptions specific to inventory issues.""" |
1292 | - |
1293 | - |
1294 | -from utah.provisioning.exceptions import UTAHProvisioningException |
1295 | - |
1296 | - |
1297 | -class UTAHProvisioningInventoryException(UTAHProvisioningException): |
1298 | - |
1299 | - """Provide a class for UTAH provisioning inventory exceptions.""" |
1300 | - |
1301 | - pass |
1302 | |
1303 | === removed file 'utah/provisioning/inventory/sqlite.py' |
1304 | --- utah/provisioning/inventory/sqlite.py 2013-04-04 14:55:25 +0000 |
1305 | +++ utah/provisioning/inventory/sqlite.py 1970-01-01 00:00:00 +0000 |
1306 | @@ -1,69 +0,0 @@ |
1307 | -# Ubuntu Testing Automation Harness |
1308 | -# Copyright 2012 Canonical Ltd. |
1309 | - |
1310 | -# This program is free software: you can redistribute it and/or modify it |
1311 | -# under the terms of the GNU General Public License version 3, as published |
1312 | -# by the Free Software Foundation. |
1313 | - |
1314 | -# This program is distributed in the hope that it will be useful, but |
1315 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
1316 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1317 | -# PURPOSE. See the GNU General Public License for more details. |
1318 | - |
1319 | -# You should have received a copy of the GNU General Public License along |
1320 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
1321 | -"""Provide base class for SQLite-based inventories.""" |
1322 | - |
1323 | - |
1324 | -import sqlite3 |
1325 | -import os |
1326 | -import logging |
1327 | - |
1328 | -from utah.provisioning.inventory.inventory import Inventory |
1329 | -from utah import config |
1330 | - |
1331 | - |
1332 | -class SQLiteInventory(Inventory): |
1333 | - |
1334 | - """Provide basic SQLite database access with a cursor.""" |
1335 | - |
1336 | - def __init__(self, db='~/.utah-sqlite-inventory', *args, **kw): |
1337 | - db = os.path.expanduser(db) |
1338 | - super(SQLiteInventory, self).__init__(*args, uniqueid=db, **kw) |
1339 | - self.db = db |
1340 | - self._connection = sqlite3.connect( |
1341 | - self.db, config.sqlite3_db_connection_timeout) |
1342 | - self._connection.isolation_level = None |
1343 | - self._connection.row_factory = sqlite3.Row |
1344 | - |
1345 | - def execute(self, sql, parameters=None): |
1346 | - """Execute SQL statement and return cursor. |
1347 | - |
1348 | - This method is expected to be used as a wrapper around all |
1349 | - `connection.execute` calls so that all the SQL statements are logged in |
1350 | - case this information is needed to troubleshoot problems. |
1351 | - |
1352 | - :param sql: A sql statement to be executed |
1353 | - :type sql: str |
1354 | - :param parameters: |
1355 | - Parameters to use to replace the placeholder |
1356 | - values in the sql statement. |
1357 | - :type parameters: |
1358 | - list (question mark placeholders) | |
1359 | - dict (colon named placeholders) |
1360 | - :returns: Cursor used to execute statement |
1361 | - :rtype: object |
1362 | - |
1363 | - """ |
1364 | - if parameters is None: |
1365 | - parameters = [] |
1366 | - |
1367 | - logging.debug('Executing SQL statement: {}, {}' |
1368 | - .format(sql, parameters)) |
1369 | - cursor = self._connection.execute(sql, parameters) |
1370 | - return cursor |
1371 | - |
1372 | - def delete(self): |
1373 | - """Remove database.""" |
1374 | - os.unlink(self.db) |
1375 | - super(SQLiteInventory, self).delete() |
1376 | |
1377 | === removed directory 'utah/provisioning/vm' |
1378 | === renamed file 'utah/provisioning/vm/vm.py' => 'utah/provisioning/vm.py' |
1379 | --- utah/provisioning/vm/vm.py 2013-04-26 17:33:15 +0000 |
1380 | +++ utah/provisioning/vm.py 2013-05-02 18:27:25 +0000 |
1381 | @@ -28,14 +28,21 @@ |
1382 | |
1383 | from utah import config |
1384 | from utah.process import ProcessChecker, ProcessRunner |
1385 | -from utah.provisioning.inventory.sqlite import SQLiteInventory |
1386 | +from utah.provisioning.exceptions import UTAHProvisioningException |
1387 | +from utah.provisioning.inventory import SQLiteInventory |
1388 | from utah.provisioning.provisioning import CustomInstallMixin, Machine |
1389 | from utah.provisioning.rsyslog import RSyslog |
1390 | from utah.provisioning.ssh import SSHMixin |
1391 | -from utah.provisioning.vm.exceptions import UTAHVMProvisioningException |
1392 | from utah.timeout import UTAHTimeout |
1393 | |
1394 | |
1395 | +class UTAHVMProvisioningException(UTAHProvisioningException): |
1396 | + |
1397 | + """Provide a foundation class for UTAH VM provisioning exceptions.""" |
1398 | + |
1399 | + pass |
1400 | + |
1401 | + |
1402 | class LibvirtVM(Machine): |
1403 | |
1404 | """Provide a class to utilize VMs using libvirt. |
1405 | |
1406 | === removed file 'utah/provisioning/vm/__init__.py' |
1407 | --- utah/provisioning/vm/__init__.py 2013-04-04 13:42:40 +0000 |
1408 | +++ utah/provisioning/vm/__init__.py 1970-01-01 00:00:00 +0000 |
1409 | @@ -1,16 +0,0 @@ |
1410 | -# Ubuntu Testing Automation Harness |
1411 | -# Copyright 2012 Canonical Ltd. |
1412 | - |
1413 | -# This program is free software: you can redistribute it and/or modify it |
1414 | -# under the terms of the GNU General Public License version 3, as published |
1415 | -# by the Free Software Foundation. |
1416 | - |
1417 | -# This program is distributed in the hope that it will be useful, but |
1418 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
1419 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1420 | -# PURPOSE. See the GNU General Public License for more details. |
1421 | - |
1422 | -# You should have received a copy of the GNU General Public License along |
1423 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
1424 | - |
1425 | -"""utah.provisioning.vm""" |
1426 | |
1427 | === removed file 'utah/provisioning/vm/exceptions.py' |
1428 | --- utah/provisioning/vm/exceptions.py 2013-04-03 17:45:59 +0000 |
1429 | +++ utah/provisioning/vm/exceptions.py 1970-01-01 00:00:00 +0000 |
1430 | @@ -1,26 +0,0 @@ |
1431 | -# Ubuntu Testing Automation Harness |
1432 | -# Copyright 2012 Canonical Ltd. |
1433 | - |
1434 | -# This program is free software: you can redistribute it and/or modify it |
1435 | -# under the terms of the GNU General Public License version 3, as published |
1436 | -# by the Free Software Foundation. |
1437 | - |
1438 | -# This program is distributed in the hope that it will be useful, but |
1439 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
1440 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1441 | -# PURPOSE. See the GNU General Public License for more details. |
1442 | - |
1443 | -# You should have received a copy of the GNU General Public License along |
1444 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
1445 | - |
1446 | -"""Provide excpetions specific to virtual machines.""" |
1447 | - |
1448 | - |
1449 | -from utah.provisioning.exceptions import UTAHProvisioningException |
1450 | - |
1451 | - |
1452 | -class UTAHVMProvisioningException(UTAHProvisioningException): |
1453 | - |
1454 | - """Provide a foundation class for UTAH VM provisioning exceptions.""" |
1455 | - |
1456 | - pass |
The test/__init__.py file was already added in the past: /code.launchpad .net/~doanac/ utah/server- cleanups/ +merge/ 159705
https:/
but it breaks packaging because the test files are included in multiple binary packages. I guess that one of this should fix the problem:
- an update to debian/*.install files
- an updated to setup.py to exclude the test package