Merge lp:~ericsnowcurrently/fake-juju/python-lib-helpers into lp:~landscape/fake-juju/trunk-old

Proposed by Eric Snow
Status: Superseded
Proposed branch: lp:~ericsnowcurrently/fake-juju/python-lib-helpers
Merge into: lp:~landscape/fake-juju/trunk-old
Diff against target: 531 lines (+493/-0)
7 files modified
python/LICENSE (+191/-0)
python/Makefile (+9/-0)
python/README.md (+1/-0)
python/fakejuju/__init__.py (+48/-0)
python/fakejuju/fakejuju.py (+45/-0)
python/fakejuju/tests/test_fakejuju.py (+130/-0)
python/setup.py (+69/-0)
To merge this branch: bzr merge lp:~ericsnowcurrently/fake-juju/python-lib-helpers
Reviewer Review Type Date Requested Status
🤖 Landscape Builder test results Approve
Landscape Pending
Landscape Pending
Review via email: mp+307891@code.launchpad.net

This proposal has been superseded by a proposal from 2016-10-06.

Description of the change

Add helper functions to the fakejuju.fakejuju module.

Testing instructions:

Run the unit tests.

To post a comment you must log in.
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: make ci-test
Result: Success
Revno: 42
Branch: lp:~ericsnowcurrently/fake-juju/python-lib-helpers
Jenkins: https://ci.lscape.net/job/latch-test-xenial/15/

review: Approve (test results)
37. By Eric Snow

Merge python-lib-init [f=] [r=chad.smith,free.ekanayaka,landscape-builder] [a=Eric Snow]
Init the Python project for a fake-juju library.

42. By Eric Snow

Move get_bootstrap_spec() to __init__.py.

43. By Eric Snow

Split the helper tests into separate test classes.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'python'
2=== added file 'python/LICENSE'
3--- python/LICENSE 1970-01-01 00:00:00 +0000
4+++ python/LICENSE 2016-10-06 22:15:11 +0000
5@@ -0,0 +1,191 @@
6+All files in this repository are licensed as follows. If you contribute
7+to this repository, it is assumed that you license your contribution
8+under the same license unless you state otherwise.
9+
10+All files Copyright (C) 2012-2016 Canonical Ltd. unless otherwise specified in the file.
11+
12+This software is licensed under the LGPLv3, included below.
13+
14+As a special exception to the GNU Lesser General Public License version 3
15+("LGPL3"), the copyright holders of this Library give you permission to
16+convey to a third party a Combined Work that links statically or dynamically
17+to this Library without providing any Minimal Corresponding Source or
18+Minimal Application Code as set out in 4d or providing the installation
19+information set out in section 4e, provided that you comply with the other
20+provisions of LGPL3 and provided that you meet, for the Application the
21+terms and conditions of the license(s) which apply to the Application.
22+
23+Except as stated in this special exception, the provisions of LGPL3 will
24+continue to comply in full to this Library. If you modify this Library, you
25+may apply this exception to your version of this Library, but you are not
26+obliged to do so. If you do not wish to do so, delete this exception
27+statement from your version. This exception does not (and cannot) modify any
28+license terms which apply to the Application, with which you must still
29+comply.
30+
31+
32+ GNU LESSER GENERAL PUBLIC LICENSE
33+ Version 3, 29 June 2007
34+
35+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
36+ Everyone is permitted to copy and distribute verbatim copies
37+ of this license document, but changing it is not allowed.
38+
39+
40+ This version of the GNU Lesser General Public License incorporates
41+the terms and conditions of version 3 of the GNU General Public
42+License, supplemented by the additional permissions listed below.
43+
44+ 0. Additional Definitions.
45+
46+ As used herein, "this License" refers to version 3 of the GNU Lesser
47+General Public License, and the "GNU GPL" refers to version 3 of the GNU
48+General Public License.
49+
50+ "The Library" refers to a covered work governed by this License,
51+other than an Application or a Combined Work as defined below.
52+
53+ An "Application" is any work that makes use of an interface provided
54+by the Library, but which is not otherwise based on the Library.
55+Defining a subclass of a class defined by the Library is deemed a mode
56+of using an interface provided by the Library.
57+
58+ A "Combined Work" is a work produced by combining or linking an
59+Application with the Library. The particular version of the Library
60+with which the Combined Work was made is also called the "Linked
61+Version".
62+
63+ The "Minimal Corresponding Source" for a Combined Work means the
64+Corresponding Source for the Combined Work, excluding any source code
65+for portions of the Combined Work that, considered in isolation, are
66+based on the Application, and not on the Linked Version.
67+
68+ The "Corresponding Application Code" for a Combined Work means the
69+object code and/or source code for the Application, including any data
70+and utility programs needed for reproducing the Combined Work from the
71+Application, but excluding the System Libraries of the Combined Work.
72+
73+ 1. Exception to Section 3 of the GNU GPL.
74+
75+ You may convey a covered work under sections 3 and 4 of this License
76+without being bound by section 3 of the GNU GPL.
77+
78+ 2. Conveying Modified Versions.
79+
80+ If you modify a copy of the Library, and, in your modifications, a
81+facility refers to a function or data to be supplied by an Application
82+that uses the facility (other than as an argument passed when the
83+facility is invoked), then you may convey a copy of the modified
84+version:
85+
86+ a) under this License, provided that you make a good faith effort to
87+ ensure that, in the event an Application does not supply the
88+ function or data, the facility still operates, and performs
89+ whatever part of its purpose remains meaningful, or
90+
91+ b) under the GNU GPL, with none of the additional permissions of
92+ this License applicable to that copy.
93+
94+ 3. Object Code Incorporating Material from Library Header Files.
95+
96+ The object code form of an Application may incorporate material from
97+a header file that is part of the Library. You may convey such object
98+code under terms of your choice, provided that, if the incorporated
99+material is not limited to numerical parameters, data structure
100+layouts and accessors, or small macros, inline functions and templates
101+(ten or fewer lines in length), you do both of the following:
102+
103+ a) Give prominent notice with each copy of the object code that the
104+ Library is used in it and that the Library and its use are
105+ covered by this License.
106+
107+ b) Accompany the object code with a copy of the GNU GPL and this license
108+ document.
109+
110+ 4. Combined Works.
111+
112+ You may convey a Combined Work under terms of your choice that,
113+taken together, effectively do not restrict modification of the
114+portions of the Library contained in the Combined Work and reverse
115+engineering for debugging such modifications, if you also do each of
116+the following:
117+
118+ a) Give prominent notice with each copy of the Combined Work that
119+ the Library is used in it and that the Library and its use are
120+ covered by this License.
121+
122+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
123+ document.
124+
125+ c) For a Combined Work that displays copyright notices during
126+ execution, include the copyright notice for the Library among
127+ these notices, as well as a reference directing the user to the
128+ copies of the GNU GPL and this license document.
129+
130+ d) Do one of the following:
131+
132+ 0) Convey the Minimal Corresponding Source under the terms of this
133+ License, and the Corresponding Application Code in a form
134+ suitable for, and under terms that permit, the user to
135+ recombine or relink the Application with a modified version of
136+ the Linked Version to produce a modified Combined Work, in the
137+ manner specified by section 6 of the GNU GPL for conveying
138+ Corresponding Source.
139+
140+ 1) Use a suitable shared library mechanism for linking with the
141+ Library. A suitable mechanism is one that (a) uses at run time
142+ a copy of the Library already present on the user's computer
143+ system, and (b) will operate properly with a modified version
144+ of the Library that is interface-compatible with the Linked
145+ Version.
146+
147+ e) Provide Installation Information, but only if you would otherwise
148+ be required to provide such information under section 6 of the
149+ GNU GPL, and only to the extent that such information is
150+ necessary to install and execute a modified version of the
151+ Combined Work produced by recombining or relinking the
152+ Application with a modified version of the Linked Version. (If
153+ you use option 4d0, the Installation Information must accompany
154+ the Minimal Corresponding Source and Corresponding Application
155+ Code. If you use option 4d1, you must provide the Installation
156+ Information in the manner specified by section 6 of the GNU GPL
157+ for conveying Corresponding Source.)
158+
159+ 5. Combined Libraries.
160+
161+ You may place library facilities that are a work based on the
162+Library side by side in a single library together with other library
163+facilities that are not Applications and are not covered by this
164+License, and convey such a combined library under terms of your
165+choice, if you do both of the following:
166+
167+ a) Accompany the combined library with a copy of the same work based
168+ on the Library, uncombined with any other library facilities,
169+ conveyed under the terms of this License.
170+
171+ b) Give prominent notice with the combined library that part of it
172+ is a work based on the Library, and explaining where to find the
173+ accompanying uncombined form of the same work.
174+
175+ 6. Revised Versions of the GNU Lesser General Public License.
176+
177+ The Free Software Foundation may publish revised and/or new versions
178+of the GNU Lesser General Public License from time to time. Such new
179+versions will be similar in spirit to the present version, but may
180+differ in detail to address new problems or concerns.
181+
182+ Each version is given a distinguishing version number. If the
183+Library as you received it specifies that a certain numbered version
184+of the GNU Lesser General Public License "or any later version"
185+applies to it, you have the option of following the terms and
186+conditions either of that published version or of any later version
187+published by the Free Software Foundation. If the Library as you
188+received it does not specify a version number of the GNU Lesser
189+General Public License, you may choose any version of the GNU Lesser
190+General Public License ever published by the Free Software Foundation.
191+
192+ If the Library as you received it specifies that a proxy can decide
193+whether future versions of the GNU Lesser General Public License shall
194+apply, that proxy's public statement of acceptance of any version is
195+permanent authorization for you to choose that version for the
196+Library.
197
198=== added file 'python/Makefile'
199--- python/Makefile 1970-01-01 00:00:00 +0000
200+++ python/Makefile 2016-10-06 22:15:11 +0000
201@@ -0,0 +1,9 @@
202+PYTHON = python
203+
204+.PHONY: test
205+test:
206+ $(PYTHON) -m unittest discover -t $(shell pwd) -s $(shell pwd)/fakejuju
207+
208+.PHONY: install-dev
209+install-dev:
210+ ln -s $(shell pwd)/fakejuju /usr/local/lib/python2.7/dist-packages/fakejuju
211
212=== added file 'python/README.md'
213--- python/README.md 1970-01-01 00:00:00 +0000
214+++ python/README.md 2016-10-06 22:15:11 +0000
215@@ -0,0 +1,1 @@
216+# fakejuju
217
218=== added directory 'python/fakejuju'
219=== added file 'python/fakejuju/__init__.py'
220--- python/fakejuju/__init__.py 1970-01-01 00:00:00 +0000
221+++ python/fakejuju/__init__.py 2016-10-06 22:15:11 +0000
222@@ -0,0 +1,48 @@
223+# Copyright 2016 Canonical Limited. All rights reserved.
224+
225+"""Support for interaction with fake-juju.
226+
227+"fake-juju" is a combination of the juju and jujud commands that is
228+suitable for use in integration tests. It exposes a limited subset
229+of the standard juju subcommands (see FakeJuju in this module for
230+specifics). When called without any arguments it runs jujud (using
231+the dummy provider) with extra logging and testing hooks available to
232+control failures. See https://launchpad.net/fake-juju for the project.
233+
234+The binary is named with the Juju version for which it was built.
235+For example, for version 1.25.6 the file is named "fake-juju-1.25.6".
236+
237+fake-juju uses the normal Juju local config directory. This defaults
238+to ~/.local/shared/juju and may be set using the JUJU_DATA environment
239+variable (in 2.x, for 1.x it is JUJU_HOME).
240+
241+In addition to all the normal Juju environment variables (e.g.
242+JUJU_DATA), fake-juju uses the following:
243+
244+ FAKE_JUJU_FAILURES - the path to the failures file
245+ The Failures class below sets this to $JUJU_DATA/juju-failures.
246+ FAKE_JUJU_LOGS_DIR - the path to the logs directory
247+ This defaults to $JUJU_DATA.
248+
249+fake-juju also creates several extra files:
250+
251+ $FAKE_JUJU_LOGS_DIR/fake-juju.log - where fake-juju logs are written
252+ $JUJU_DATA/fakejuju - fake-juju's data cache
253+ $JUJU_DATA/fifo - a FIFO file that triggers jujud shutdown
254+ $JUJU_DATA/cert.ca - the API's CA certificate
255+
256+Normal Juju logging for is written to $JUJU_DATA/fake-juju.log.
257+
258+Failures may be injected into a running fake-juju (or set before
259+running). They may be injected by adding them to the file identified
260+by $FAKE_JUJU_FAILURES. The format is a single failure definition per
261+line. The syntax of the failure definition depends on the failure.
262+The currently supported failures (with their definition syntax) are
263+listed here:
264+
265+ * when adding a unit with a specific ID
266+ format: "unit-<ID>" (e.g. unit-mysql/0)
267+
268+"""
269+
270+__version__ = "0.9.0b1"
271
272=== added file 'python/fakejuju/fakejuju.py'
273--- python/fakejuju/fakejuju.py 1970-01-01 00:00:00 +0000
274+++ python/fakejuju/fakejuju.py 2016-10-06 22:15:11 +0000
275@@ -0,0 +1,45 @@
276+# Copyright 2016 Canonical Limited. All rights reserved.
277+
278+import os.path
279+
280+import txjuju.cli
281+
282+
283+def get_bootstrap_spec(name, admin_secret=None):
284+ """Return the BootstrapSpec instance for the given controller.
285+
286+ @param name: The controller name to set up.
287+ @param admin_secret: The admin user password to use.
288+ """
289+ type = "dummy"
290+ default_series = None # Use the default.
291+ return txjuju.cli.BootstrapSpec(name, type, default_series, admin_secret)
292+
293+
294+def get_filename(version, bindir=None):
295+ """Return the full path to the fake-juju binary for the given version.
296+
297+ @param version: The Juju version to use.
298+ @param bindir: The directory containing the fake-juju binary.
299+ This defaults to /usr/bin.
300+ """
301+ if not version:
302+ raise ValueError("version not provided")
303+ filename = "fake-juju-{}".format(version)
304+ if bindir is None:
305+ # XXX Search $PATH.
306+ bindir = "/usr/bin"
307+ return os.path.join(bindir, filename)
308+
309+
310+def set_envvars(envvars, failures_filename=None, logsdir=None):
311+ """Return the environment variables with which to run fake-juju.
312+
313+ @param envvars: The env dict to update.
314+ @param failures_filename: The path to the failures file that
315+ fake-juju will use.
316+ @params logsdir: The path to the directory where fake-juju will
317+ write its log files.
318+ """
319+ envvars["FAKE_JUJU_FAILURES"] = failures_filename or ""
320+ envvars["FAKE_JUJU_LOGS_DIR"] = logsdir or ""
321
322=== added directory 'python/fakejuju/tests'
323=== added file 'python/fakejuju/tests/__init__.py'
324=== added file 'python/fakejuju/tests/test_fakejuju.py'
325--- python/fakejuju/tests/test_fakejuju.py 1970-01-01 00:00:00 +0000
326+++ python/fakejuju/tests/test_fakejuju.py 2016-10-06 22:15:11 +0000
327@@ -0,0 +1,130 @@
328+# Copyright 2016 Canonical Limited. All rights reserved.
329+
330+import unittest
331+
332+import txjuju.cli
333+
334+from fakejuju.fakejuju import get_bootstrap_spec, get_filename, set_envvars
335+
336+
337+class HelperTests(unittest.TestCase):
338+
339+ def test_get_bootstrap_spec_full(self):
340+ """get_bootstrap_spec() works correctly when given all args."""
341+ spec = get_bootstrap_spec("my-env", "pw")
342+
343+ self.assertEqual(
344+ spec,
345+ txjuju.cli.BootstrapSpec("my-env", "dummy", admin_secret="pw"))
346+
347+ def test_get_bootstrap_spec_minimal(self):
348+ """get_bootstrap_spec() works correctly when given minimal args."""
349+ spec = get_bootstrap_spec("my-env")
350+
351+ self.assertEqual(spec, txjuju.cli.BootstrapSpec("my-env", "dummy"))
352+
353+ def test_get_filename_full(self):
354+ """get_filename() works correctly when given all args."""
355+ filename = get_filename("1.25.6", "/spam")
356+
357+ self.assertEqual(filename, "/spam/fake-juju-1.25.6")
358+
359+ def test_get_filename_minimal(self):
360+ """get_filename() works correctly when given minimal args."""
361+ filename = get_filename("1.25.6")
362+
363+ self.assertEqual(filename, "/usr/bin/fake-juju-1.25.6")
364+
365+ def test_get_filename_empty_bindir(self):
366+ """get_filename() works correctly when given an empty string
367+ for bindir."""
368+ filename = get_filename("1.25.6", "")
369+
370+ self.assertEqual(filename, "fake-juju-1.25.6")
371+
372+ def test_get_filename_missing_version(self):
373+ """get_filename() fails if version is None or empty."""
374+ with self.assertRaises(ValueError):
375+ get_filename(None)
376+ with self.assertRaises(ValueError):
377+ get_filename("")
378+
379+ def test_set_envvars_full(self):
380+ """set_envvars() works correctly when given all args."""
381+ envvars = {}
382+ set_envvars(envvars, "/spam/failures", "/eggs/logsdir")
383+
384+ self.assertEqual(envvars, {
385+ "FAKE_JUJU_FAILURES": "/spam/failures",
386+ "FAKE_JUJU_LOGS_DIR": "/eggs/logsdir",
387+ })
388+
389+ def test_set_envvars_minimal(self):
390+ """set_envvars() works correctly when given minimal args."""
391+ envvars = {}
392+ set_envvars(envvars)
393+
394+ self.assertEqual(envvars, {
395+ "FAKE_JUJU_FAILURES": "",
396+ "FAKE_JUJU_LOGS_DIR": "",
397+ })
398+
399+ def test_set_envvars_start_empty(self):
400+ """set_envvars() sets all values on an empty dict."""
401+ envvars = {}
402+ set_envvars(envvars, "x", "y")
403+
404+ self.assertEqual(envvars, {
405+ "FAKE_JUJU_FAILURES": "x",
406+ "FAKE_JUJU_LOGS_DIR": "y",
407+ })
408+
409+ def test_set_envvars_no_collisions(self):
410+ """set_envvars() sets all values when none are set yet."""
411+ envvars = {"SPAM": "eggs"}
412+ set_envvars(envvars, "x", "y")
413+
414+ self.assertEqual(envvars, {
415+ "SPAM": "eggs",
416+ "FAKE_JUJU_FAILURES": "x",
417+ "FAKE_JUJU_LOGS_DIR": "y",
418+ })
419+
420+ def test_set_envvars_empty_to_nonempty(self):
421+ """set_envvars() updates empty values."""
422+ envvars = {
423+ "FAKE_JUJU_FAILURES": "",
424+ "FAKE_JUJU_LOGS_DIR": "",
425+ }
426+ set_envvars(envvars, "x", "y")
427+
428+ self.assertEqual(envvars, {
429+ "FAKE_JUJU_FAILURES": "x",
430+ "FAKE_JUJU_LOGS_DIR": "y",
431+ })
432+
433+ def test_set_envvars_nonempty_to_nonempty(self):
434+ """set_envvars() overwrites existing values."""
435+ envvars = {
436+ "FAKE_JUJU_FAILURES": "spam",
437+ "FAKE_JUJU_LOGS_DIR": "ham",
438+ }
439+ set_envvars(envvars, "x", "y")
440+
441+ self.assertEqual(envvars, {
442+ "FAKE_JUJU_FAILURES": "x",
443+ "FAKE_JUJU_LOGS_DIR": "y",
444+ })
445+
446+ def test_set_envvars_nonempty_to_empty(self):
447+ """set_envvars() with no args "unsets" existing values."""
448+ envvars = {
449+ "FAKE_JUJU_FAILURES": "x",
450+ "FAKE_JUJU_LOGS_DIR": "y",
451+ }
452+ set_envvars(envvars)
453+
454+ self.assertEqual(envvars, {
455+ "FAKE_JUJU_FAILURES": "",
456+ "FAKE_JUJU_LOGS_DIR": "",
457+ })
458
459=== added file 'python/setup.py'
460--- python/setup.py 1970-01-01 00:00:00 +0000
461+++ python/setup.py 2016-10-06 22:15:11 +0000
462@@ -0,0 +1,69 @@
463+import os
464+from importlib import import_module
465+try:
466+ from setuptools import setup
467+except ImportError:
468+ from distutils.core import setup
469+
470+
471+basedir = os.path.abspath(os.path.dirname(__file__) or '.')
472+
473+# required data
474+
475+package_name = 'fakejuju'
476+NAME = package_name
477+SUMMARY = 'A limited adaptation of Juju\'s client, with testing hooks.'
478+AUTHOR = 'Canonical Landscape team'
479+EMAIL = 'juju@lists.ubuntu.com'
480+PROJECT_URL = 'https://launchpad.net/fake-juju'
481+LICENSE = 'LGPLv3'
482+
483+with open(os.path.join(basedir, 'README.md')) as readme_file:
484+ DESCRIPTION = readme_file.read()
485+
486+# dymanically generated data
487+
488+VERSION = import_module(package_name).__version__
489+
490+# set up packages
491+
492+exclude_dirs = [
493+ 'tests',
494+ ]
495+
496+PACKAGES = []
497+for path, dirs, files in os.walk(package_name):
498+ if "__init__.py" not in files:
499+ continue
500+ path = path.split(os.sep)
501+ if path[-1] in exclude_dirs:
502+ continue
503+ PACKAGES.append(".".join(path))
504+
505+# dependencies
506+
507+DEPS = ['yaml',
508+ # for testing
509+ 'txjuju',
510+ 'fixtures',
511+ 'testtools',
512+ ]
513+
514+
515+if __name__ == "__main__":
516+ setup(name=NAME,
517+ version=VERSION,
518+ author=AUTHOR,
519+ author_email=EMAIL,
520+ url=PROJECT_URL,
521+ license=LICENSE,
522+ description=SUMMARY,
523+ long_description=DESCRIPTION,
524+ packages=PACKAGES,
525+
526+ # for distutils
527+ requires=DEPS,
528+
529+ # for setuptools
530+ install_requires=DEPS,
531+ )

Subscribers

People subscribed via source and target branches

to all changes: