Merge lp:~free.ekanayaka/landscape-charm/install-from-deb into lp:~landscape/landscape-charm/trunk
- install-from-deb
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Free Ekanayaka |
Approved revision: | 242 |
Merged at revision: | 231 |
Proposed branch: | lp:~free.ekanayaka/landscape-charm/install-from-deb |
Merge into: | lp:~landscape/landscape-charm/trunk |
Diff against target: |
508 lines (+353/-50) 9 files modified
hooks/config-changed (+9/-0) hooks/lib/apt.py (+126/-19) hooks/lib/config.py (+23/-0) hooks/lib/install.py (+24/-0) hooks/lib/tests/helpers.py (+1/-1) hooks/lib/tests/stubs.py (+7/-3) hooks/lib/tests/test_apt.py (+115/-27) hooks/lib/tests/test_config.py (+25/-0) hooks/lib/tests/test_install.py (+23/-0) |
To merge this branch: | bzr merge lp:~free.ekanayaka/landscape-charm/install-from-deb |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Adam Collard (community) | Approve | ||
Björn Tillenius (community) | Approve | ||
🤖 Landscape Builder | test results | Approve | |
Review via email:
|
Commit message
This branch adds support for installing landscape-server packages built from a local tarball.
Description of the change
This branch adds support for installing landscape-server packages built from a local tarball.
To test it:
bzr branch lp:~free.ekanayaka/landscape-charm/install-from-deb
mkdir trusty
cd trusty
ln -s ../install-from-deb landscape-server
cd ..
# Let's build a tarball from a branch that hasn't landed yet
bzr branch lp:~free.ekanayaka/landscape/pingserver-head
cd pingserver-head
make build
cd standalone
make standalone-
mv landscape-
cd ../..
# Copy this https:/
juju-deployer -vdW -w 180 -c deployer.yaml landscape
Then notice that the deployed package was built from the tarball, and
the pingserver actually answers HEAD requests.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
🤖 Landscape Builder (landscape-builder) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Adam Collard (adam-collard) : | # |
- 241. By Free Ekanayaka
-
Use hashlib instead of os.system
- 242. By Free Ekanayaka
-
Address review comments
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Free Ekanayaka (free.ekanayaka) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
🤖 Landscape Builder (landscape-builder) wrote : | # |
Command: make ci-test
Result: Success
Revno: 242
Branch: lp:~free.ekanayaka/landscape-charm/install-from-deb
Jenkins: https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Björn Tillenius (bjornt) wrote : | # |
+1 with Adam's comments addressed. Ideally I would have like some more functional tests, since checking subprocess call parameters is really fragile. But I appreciate that issuing real commands isn't trivial.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Free Ekanayaka (free.ekanayaka) wrote : | # |
> +1 with Adam's comments addressed. Ideally I would have like some more
> functional tests, since checking subprocess call parameters is really fragile.
> But I appreciate that issuing real commands isn't trivial.
Right. Note that this code is only meaningful for development, is not production code.
Preview Diff
1 | === added file 'hooks/config-changed' | |||
2 | --- hooks/config-changed 1970-01-01 00:00:00 +0000 | |||
3 | +++ hooks/config-changed 2015-03-09 11:56:41 +0000 | |||
4 | @@ -0,0 +1,9 @@ | |||
5 | 1 | #!/usr/bin/python | ||
6 | 2 | import sys | ||
7 | 3 | |||
8 | 4 | from lib.config import ConfigHook | ||
9 | 5 | |||
10 | 6 | |||
11 | 7 | if __name__ == "__main__": | ||
12 | 8 | hook = ConfigHook() | ||
13 | 9 | sys.exit(hook()) | ||
14 | 0 | 10 | ||
15 | === renamed file 'hooks/lib/install.py' => 'hooks/lib/apt.py' | |||
16 | --- hooks/lib/install.py 2015-01-28 11:53:18 +0000 | |||
17 | +++ hooks/lib/apt.py 2015-03-09 11:56:41 +0000 | |||
18 | @@ -1,31 +1,138 @@ | |||
19 | 1 | import glob | ||
20 | 2 | import hashlib | ||
21 | 3 | import os | ||
22 | 4 | import shutil | ||
23 | 5 | import subprocess | ||
24 | 6 | |||
25 | 1 | from charmhelpers import fetch | 7 | from charmhelpers import fetch |
26 | 8 | from charmhelpers.core import hookenv | ||
27 | 2 | 9 | ||
29 | 3 | from lib.hook import Hook, HookError | 10 | from lib.hook import HookError |
30 | 4 | 11 | ||
31 | 5 | PACKAGES = ("landscape-server",) | 12 | PACKAGES = ("landscape-server",) |
39 | 6 | 13 | PACKAGES_DEV = ("dpkg-dev", "pbuilder") | |
40 | 7 | 14 | TARBALL = "landscape-server_*.tar.gz" | |
41 | 8 | class InstallHook(Hook): | 15 | |
42 | 9 | """Execute install hook logic.""" | 16 | # XXX Default options taken from charmhelpers, there's no way to just |
43 | 10 | 17 | # extend them. | |
44 | 11 | def __init__(self, fetch=fetch, **kwargs): | 18 | DEFAULT_INSTALL_OPTIONS = ("--option=Dpkg::Options::=--force-confold",) |
45 | 12 | super(InstallHook, self).__init__(**kwargs) | 19 | |
46 | 20 | # Shell commands to build the debs and publish them in a local repository | ||
47 | 21 | BUILD_LOCAL_ARCHIVE = """ | ||
48 | 22 | dch -v 9999:$(dpkg-parsechangelog|grep ^Version:|cut -d ' ' -f 2) \ | ||
49 | 23 | development --distribution $(lsb_release -cs) && | ||
50 | 24 | /usr/lib/pbuilder/pbuilder-satisfydepends && | ||
51 | 25 | dpkg-buildpackage -us -uc && | ||
52 | 26 | mv ../*.deb . && | ||
53 | 27 | dpkg-scanpackages -m . /dev/null > Packages && | ||
54 | 28 | cat Packages | bzip2 -9 > Packages.bz2 && | ||
55 | 29 | cat Packages | gzip -9 > Packages.gz && | ||
56 | 30 | dpkg-scansources . > Sources && | ||
57 | 31 | cat Sources | bzip2 -9 > Sources.bz2 && | ||
58 | 32 | cat Sources | gzip -9 > Sources.gz && | ||
59 | 33 | apt-ftparchive release . > Release | ||
60 | 34 | """ | ||
61 | 35 | |||
62 | 36 | |||
63 | 37 | class Apt(object): | ||
64 | 38 | """Perform APT-related tasks as setting sources and installing packages. | ||
65 | 39 | |||
66 | 40 | This is a thin facade around C{charmhelpers.fetch}, offering some | ||
67 | 41 | additional features, like building Landscape packages from a local | ||
68 | 42 | tarball. | ||
69 | 43 | """ | ||
70 | 44 | |||
71 | 45 | def __init__(self, hookenv=hookenv, fetch=fetch, subprocess=subprocess): | ||
72 | 46 | self._hookenv = hookenv | ||
73 | 13 | self._fetch = fetch | 47 | self._fetch = fetch |
80 | 14 | 48 | self._subprocess = subprocess | |
81 | 15 | def _run(self): | 49 | |
82 | 16 | self._configure_sources() | 50 | def set_sources(self): |
77 | 17 | self._install_packages() | ||
78 | 18 | |||
79 | 19 | def _configure_sources(self): | ||
83 | 20 | """Configure the extra APT sources to use.""" | 51 | """Configure the extra APT sources to use.""" |
84 | 52 | needs_update = False | ||
85 | 53 | if self._set_remote_source(): | ||
86 | 54 | needs_update = True | ||
87 | 55 | if self._set_local_source(): | ||
88 | 56 | needs_update = True | ||
89 | 57 | if needs_update: | ||
90 | 58 | self._fetch.apt_update(fatal=True) | ||
91 | 59 | |||
92 | 60 | def install_packages(self): | ||
93 | 61 | """Install the needed packages.""" | ||
94 | 62 | options = list(DEFAULT_INSTALL_OPTIONS) | ||
95 | 63 | if self._get_local_tarball() is not None: | ||
96 | 64 | # We don't sign the locally built repository, so we need to tell | ||
97 | 65 | # apt-get that we don't care. | ||
98 | 66 | options.append("--allow-unauthenticated") | ||
99 | 67 | packages = self._fetch.filter_installed_packages(PACKAGES) | ||
100 | 68 | self._fetch.apt_install(packages, options=options, fatal=True) | ||
101 | 69 | |||
102 | 70 | def _set_remote_source(self): | ||
103 | 71 | """Set the remote APT repository to use, if new or changed.""" | ||
104 | 21 | config = self._hookenv.config() | 72 | config = self._hookenv.config() |
105 | 22 | source = config.get("source") | 73 | source = config.get("source") |
106 | 23 | if not source: | 74 | if not source: |
107 | 24 | raise HookError("No source config parameter defined") | 75 | raise HookError("No source config parameter defined") |
108 | 76 | previous_source = config.previous("source") | ||
109 | 77 | |||
110 | 78 | # Check if we're setting the source for the first time, or replacing | ||
111 | 79 | # an existing value. In the latter case we'll no-op if the value is the | ||
112 | 80 | # same or take care to remove it from sources.list if it's not. | ||
113 | 81 | previous_source = config.previous("source") | ||
114 | 82 | if previous_source is not None: | ||
115 | 83 | if previous_source == source: | ||
116 | 84 | return False | ||
117 | 85 | self._subprocess.check_call( | ||
118 | 86 | ["add-apt-repository", "--remove", "--yes", previous_source]) | ||
119 | 87 | |||
120 | 25 | self._fetch.add_source(source, config.get("key")) | 88 | self._fetch.add_source(source, config.get("key")) |
126 | 26 | self._fetch.apt_update(fatal=True) | 89 | |
127 | 27 | 90 | return True | |
128 | 28 | def _install_packages(self): | 91 | |
129 | 29 | """Install the needed packages.""" | 92 | def _set_local_source(self): |
130 | 30 | packages = self._fetch.filter_installed_packages(PACKAGES) | 93 | """Set the local APT repository for the Landscape tarball, if any.""" |
131 | 94 | tarball = self._get_local_tarball() | ||
132 | 95 | if tarball is None: | ||
133 | 96 | return False | ||
134 | 97 | |||
135 | 98 | if not self._is_tarball_new(tarball): | ||
136 | 99 | return False | ||
137 | 100 | |||
138 | 101 | packages = self._fetch.filter_installed_packages(PACKAGES_DEV) | ||
139 | 31 | self._fetch.apt_install(packages, fatal=True) | 102 | self._fetch.apt_install(packages, fatal=True) |
140 | 103 | |||
141 | 104 | build_dir = os.path.join(self._hookenv.charm_dir(), "build") | ||
142 | 105 | shutil.rmtree(build_dir, ignore_errors=True) | ||
143 | 106 | os.mkdir(build_dir) | ||
144 | 107 | |||
145 | 108 | self._subprocess.check_call( | ||
146 | 109 | ["tar", "--strip=1", "-xf", tarball], cwd=build_dir) | ||
147 | 110 | self._subprocess.check_call( | ||
148 | 111 | BUILD_LOCAL_ARCHIVE, shell=True, cwd=build_dir) | ||
149 | 112 | |||
150 | 113 | self._fetch.add_source("deb file://%s/ ./" % build_dir) | ||
151 | 114 | |||
152 | 115 | return True | ||
153 | 116 | |||
154 | 117 | def _get_local_tarball(self): | ||
155 | 118 | """Return the local Landscape tarball if any, C{None} otherwise.""" | ||
156 | 119 | matches = glob.glob(os.path.join(self._hookenv.charm_dir(), TARBALL)) | ||
157 | 120 | return matches[0] if matches else None | ||
158 | 121 | |||
159 | 122 | def _is_tarball_new(self, tarball): | ||
160 | 123 | """Check if this is a new tarball and we need to build it.""" | ||
161 | 124 | with open(tarball, "r") as fd: | ||
162 | 125 | digest = hashlib.md5(fd.read()).hexdigest() | ||
163 | 126 | |||
164 | 127 | md5sum = tarball + ".md5sum" | ||
165 | 128 | if os.path.exists(md5sum): | ||
166 | 129 | with open(md5sum, "r") as fd: | ||
167 | 130 | if fd.read() == digest: | ||
168 | 131 | # The checksum matches, so it's not a new tarball | ||
169 | 132 | return False | ||
170 | 133 | |||
171 | 134 | # Update the md5sum file, since this is a new tarball. | ||
172 | 135 | with open(md5sum, "w") as fd: | ||
173 | 136 | fd.write(digest) | ||
174 | 137 | |||
175 | 138 | return True | ||
176 | 32 | 139 | ||
177 | === added file 'hooks/lib/config.py' | |||
178 | --- hooks/lib/config.py 1970-01-01 00:00:00 +0000 | |||
179 | +++ hooks/lib/config.py 2015-03-09 11:56:41 +0000 | |||
180 | @@ -0,0 +1,23 @@ | |||
181 | 1 | import subprocess | ||
182 | 2 | |||
183 | 3 | from charmhelpers import fetch | ||
184 | 4 | from charmhelpers.core import hookenv | ||
185 | 5 | |||
186 | 6 | from lib.hook import Hook | ||
187 | 7 | from lib.apt import Apt | ||
188 | 8 | |||
189 | 9 | |||
190 | 10 | class ConfigHook(Hook): | ||
191 | 11 | """Execute config-changed hook logic.""" | ||
192 | 12 | |||
193 | 13 | def __init__(self, hookenv=hookenv, fetch=fetch, subprocess=subprocess): | ||
194 | 14 | super(ConfigHook, self).__init__(hookenv=hookenv) | ||
195 | 15 | self._fetch = fetch | ||
196 | 16 | self._subprocess = subprocess | ||
197 | 17 | |||
198 | 18 | def _run(self): | ||
199 | 19 | # Re-set APT sources, if the have changed. | ||
200 | 20 | apt = Apt( | ||
201 | 21 | hookenv=self._hookenv, fetch=self._fetch, | ||
202 | 22 | subprocess=self._subprocess) | ||
203 | 23 | apt.set_sources() | ||
204 | 0 | 24 | ||
205 | === added file 'hooks/lib/install.py' | |||
206 | --- hooks/lib/install.py 1970-01-01 00:00:00 +0000 | |||
207 | +++ hooks/lib/install.py 2015-03-09 11:56:41 +0000 | |||
208 | @@ -0,0 +1,24 @@ | |||
209 | 1 | import subprocess | ||
210 | 2 | |||
211 | 3 | from charmhelpers import fetch | ||
212 | 4 | from charmhelpers.core import hookenv | ||
213 | 5 | |||
214 | 6 | from lib.hook import Hook | ||
215 | 7 | from lib.apt import Apt | ||
216 | 8 | |||
217 | 9 | |||
218 | 10 | class InstallHook(Hook): | ||
219 | 11 | """Execute install hook logic.""" | ||
220 | 12 | |||
221 | 13 | def __init__(self, hookenv=hookenv, fetch=fetch, subprocess=subprocess): | ||
222 | 14 | super(InstallHook, self).__init__(hookenv=hookenv) | ||
223 | 15 | self._fetch = fetch | ||
224 | 16 | self._subprocess = subprocess | ||
225 | 17 | |||
226 | 18 | def _run(self): | ||
227 | 19 | # Set APT sources and install Landscape packages | ||
228 | 20 | apt = Apt( | ||
229 | 21 | hookenv=self._hookenv, fetch=self._fetch, | ||
230 | 22 | subprocess=self._subprocess) | ||
231 | 23 | apt.set_sources() | ||
232 | 24 | apt.install_packages() | ||
233 | 0 | 25 | ||
234 | === modified file 'hooks/lib/tests/helpers.py' | |||
235 | --- hooks/lib/tests/helpers.py 2015-01-29 09:55:59 +0000 | |||
236 | +++ hooks/lib/tests/helpers.py 2015-03-09 11:56:41 +0000 | |||
237 | @@ -26,7 +26,7 @@ | |||
238 | 26 | # upstream. | 26 | # upstream. |
239 | 27 | charm_dir = self.useFixture(TempDir()) | 27 | charm_dir = self.useFixture(TempDir()) |
240 | 28 | self.useFixture(EnvironmentVariable("CHARM_DIR", charm_dir.path)) | 28 | self.useFixture(EnvironmentVariable("CHARM_DIR", charm_dir.path)) |
242 | 29 | self.hookenv = HookenvStub() | 29 | self.hookenv = HookenvStub(charm_dir.path) |
243 | 30 | 30 | ||
244 | 31 | if self.with_hookenv_monkey_patch: | 31 | if self.with_hookenv_monkey_patch: |
245 | 32 | self._monkey_patch_hookenv() | 32 | self._monkey_patch_hookenv() |
246 | 33 | 33 | ||
247 | === modified file 'hooks/lib/tests/stubs.py' | |||
248 | --- hooks/lib/tests/stubs.py 2015-03-02 12:39:25 +0000 | |||
249 | +++ hooks/lib/tests/stubs.py 2015-03-09 11:56:41 +0000 | |||
250 | @@ -9,10 +9,11 @@ | |||
251 | 9 | unit = "landscape-server/0" | 9 | unit = "landscape-server/0" |
252 | 10 | relid = None | 10 | relid = None |
253 | 11 | 11 | ||
255 | 12 | def __init__(self): | 12 | def __init__(self, charm_dir): |
256 | 13 | self.messages = [] | 13 | self.messages = [] |
257 | 14 | self.relations = {} | 14 | self.relations = {} |
258 | 15 | self._config = Config() | 15 | self._config = Config() |
259 | 16 | self._charm_dir = charm_dir | ||
260 | 16 | 17 | ||
261 | 17 | def config(self): | 18 | def config(self): |
262 | 18 | return self._config | 19 | return self._config |
263 | @@ -58,6 +59,9 @@ | |||
264 | 58 | def relation_set(self, rid=None, relation_settings=None, **kwargs): | 59 | def relation_set(self, rid=None, relation_settings=None, **kwargs): |
265 | 59 | self.relations[rid] = relation_settings | 60 | self.relations[rid] = relation_settings |
266 | 60 | 61 | ||
267 | 62 | def charm_dir(self): | ||
268 | 63 | return self._charm_dir | ||
269 | 64 | |||
270 | 61 | 65 | ||
271 | 62 | class FetchStub(object): | 66 | class FetchStub(object): |
272 | 63 | """Provide a testable stub for C{charmhelpers.fetch}.""" | 67 | """Provide a testable stub for C{charmhelpers.fetch}.""" |
273 | @@ -78,8 +82,8 @@ | |||
274 | 78 | self.filtered.append(packages) | 82 | self.filtered.append(packages) |
275 | 79 | return packages | 83 | return packages |
276 | 80 | 84 | ||
279 | 81 | def apt_install(self, packages, fatal=False): | 85 | def apt_install(self, packages, options=None, fatal=False): |
280 | 82 | self.installed.append((packages, fatal)) | 86 | self.installed.append((packages, options, fatal)) |
281 | 83 | 87 | ||
282 | 84 | 88 | ||
283 | 85 | class ClusterStub(object): | 89 | class ClusterStub(object): |
284 | 86 | 90 | ||
285 | === renamed file 'hooks/lib/tests/test_install.py' => 'hooks/lib/tests/test_apt.py' | |||
286 | --- hooks/lib/tests/test_install.py 2015-01-21 20:37:36 +0000 | |||
287 | +++ hooks/lib/tests/test_apt.py 2015-03-09 11:56:41 +0000 | |||
288 | @@ -1,37 +1,110 @@ | |||
290 | 1 | from charmhelpers.core.hookenv import ERROR | 1 | import os |
291 | 2 | 2 | ||
294 | 3 | from lib.install import InstallHook, PACKAGES | 3 | from lib.apt import Apt, PACKAGES, BUILD_LOCAL_ARCHIVE, DEFAULT_INSTALL_OPTIONS |
295 | 4 | from lib.tests.stubs import FetchStub | 4 | from lib.hook import HookError |
296 | 5 | from lib.tests.stubs import FetchStub, SubprocessStub | ||
297 | 5 | from lib.tests.helpers import HookenvTest | 6 | from lib.tests.helpers import HookenvTest |
298 | 6 | 7 | ||
299 | 7 | 8 | ||
301 | 8 | class InstallHookTest(HookenvTest): | 9 | class AptTest(HookenvTest): |
302 | 9 | 10 | ||
303 | 10 | def setUp(self): | 11 | def setUp(self): |
305 | 11 | super(InstallHookTest, self).setUp() | 12 | super(AptTest, self).setUp() |
306 | 12 | self.fetch = FetchStub() | 13 | self.fetch = FetchStub() |
310 | 13 | self.hook = InstallHook( | 14 | self.subprocess = SubprocessStub() |
311 | 14 | fetch=self.fetch, | 15 | self.apt = Apt( |
312 | 15 | hookenv=self.hookenv) | 16 | hookenv=self.hookenv, fetch=self.fetch, subprocess=self.subprocess) |
313 | 16 | 17 | ||
314 | 17 | def test_no_source(self): | 18 | def test_no_source(self): |
315 | 18 | """ | 19 | """ |
332 | 19 | If no APT source is defined the install hook logs an error | 20 | If no APT source is defined, we fail with a L{HookError}. |
333 | 20 | message and exists with code 1. | 21 | """ |
334 | 21 | """ | 22 | with self.assertRaises(HookError) as error: |
335 | 22 | self.assertEqual(1, self.hook()) | 23 | self.apt.set_sources() |
336 | 23 | self.assertEqual( | 24 | self.assertEqual( |
337 | 24 | ("No source config parameter defined", ERROR), | 25 | "No source config parameter defined", str(error.exception)) |
338 | 25 | self.hookenv.messages[-1]) | 26 | |
339 | 26 | 27 | def test_set_sources(self): | |
340 | 27 | def test_add_source(self): | 28 | """ |
341 | 28 | """ | 29 | The C{set_sources} method adds the configured APT source and |
342 | 29 | The install hook adds the configured APT source and refreshes it. | 30 | refreshes it. |
343 | 30 | """ | 31 | """ |
344 | 31 | self.hookenv.config()["source"] = "ppa:landscape/14.10" | 32 | self.hookenv.config()["source"] = "ppa:landscape/14.10" |
345 | 32 | self.assertEqual(0, self.hook()) | 33 | self.apt.set_sources() |
346 | 33 | self.assertEqual([("ppa:landscape/14.10", None)], self.fetch.sources) | 34 | self.assertEqual([("ppa:landscape/14.10", None)], self.fetch.sources) |
347 | 34 | self.assertEqual([True], self.fetch.updates) | 35 | self.assertEqual([True], self.fetch.updates) |
348 | 36 | |||
349 | 37 | def test_set_sources_not_changed(self): | ||
350 | 38 | """ | ||
351 | 39 | The C{set_sources} method is a no-op if the source config hasn't | ||
352 | 40 | changed. | ||
353 | 41 | """ | ||
354 | 42 | config = self.hookenv.config() | ||
355 | 43 | config["source"] = "ppa:landscape/14.10" | ||
356 | 44 | config.save() | ||
357 | 45 | config.load_previous() | ||
358 | 46 | self.apt.set_sources() | ||
359 | 47 | self.assertEqual([], self.fetch.sources) | ||
360 | 48 | self.assertEqual([], self.fetch.updates) | ||
361 | 49 | |||
362 | 50 | def test_set_sources_replace(self): | ||
363 | 51 | """ | ||
364 | 52 | The C{set_sources} method removes any previous source before setting | ||
365 | 53 | the new one. | ||
366 | 54 | """ | ||
367 | 55 | config = self.hookenv.config() | ||
368 | 56 | config["source"] = "ppa:landscape/14.10" | ||
369 | 57 | config.save() | ||
370 | 58 | config.load_previous() | ||
371 | 59 | config["source"] = "ppa:landscape/15.01" | ||
372 | 60 | self.apt.set_sources() | ||
373 | 61 | self.assertEqual( | ||
374 | 62 | ["add-apt-repository", "--remove", "--yes", "ppa:landscape/14.10"], | ||
375 | 63 | self.subprocess.calls[0][0]) | ||
376 | 64 | self.assertEqual([("ppa:landscape/15.01", None)], self.fetch.sources) | ||
377 | 65 | self.assertEqual([True], self.fetch.updates) | ||
378 | 66 | |||
379 | 67 | def test_local_tarball(self): | ||
380 | 68 | """ | ||
381 | 69 | If a Landscape tarball is found, the C{set_sources} method builds local | ||
382 | 70 | repository with the relevant deb packages. | ||
383 | 71 | """ | ||
384 | 72 | self.hookenv.config()["source"] = "ppa:landscape/14.10" | ||
385 | 73 | tarball = os.path.join( | ||
386 | 74 | self.hookenv.charm_dir(), "landscape-server_1.2.3.tar.gz") | ||
387 | 75 | with open(tarball, "w") as fd: | ||
388 | 76 | fd.write("") | ||
389 | 77 | self.apt.set_sources() | ||
390 | 78 | |||
391 | 79 | build_dir = os.path.join(self.hookenv.charm_dir(), "build") | ||
392 | 80 | |||
393 | 81 | self.assertEqual( | ||
394 | 82 | [(["tar", "--strip=1", "-xf", tarball], {"cwd": build_dir}), | ||
395 | 83 | (BUILD_LOCAL_ARCHIVE, {"shell": True, "cwd": build_dir})], | ||
396 | 84 | self.subprocess.calls) | ||
397 | 85 | |||
398 | 86 | self.assertEqual( | ||
399 | 87 | [("ppa:landscape/14.10", None), | ||
400 | 88 | ("deb file://%s/build/ ./" % self.hookenv.charm_dir(), None)], | ||
401 | 89 | self.fetch.sources) | ||
402 | 90 | |||
403 | 91 | def test_local_tarball_not_new(self): | ||
404 | 92 | """ | ||
405 | 93 | If the landscape tarball hasn't changed, it won't be built. | ||
406 | 94 | """ | ||
407 | 95 | self.hookenv.config()["source"] = "ppa:landscape/14.10" | ||
408 | 96 | tarball = os.path.join( | ||
409 | 97 | self.hookenv.charm_dir(), "landscape-server_1.2.3.tar.gz") | ||
410 | 98 | with open(tarball, "w") as fd: | ||
411 | 99 | fd.write("data") | ||
412 | 100 | self.apt.set_sources() | ||
413 | 101 | |||
414 | 102 | # Reset the recorded sources and subprocess calls and run again | ||
415 | 103 | self.subprocess.calls[:] = [] | ||
416 | 104 | self.fetch.sources[:] = [] | ||
417 | 105 | self.apt.set_sources() | ||
418 | 106 | self.assertEqual([], self.subprocess.calls) | ||
419 | 107 | self.assertEqual([("ppa:landscape/14.10", None)], self.fetch.sources) | ||
420 | 35 | 108 | ||
421 | 36 | def test_packages(self): | 109 | def test_packages(self): |
422 | 37 | """ | 110 | """ |
423 | @@ -41,9 +114,24 @@ | |||
424 | 41 | 114 | ||
425 | 42 | def test_install(self): | 115 | def test_install(self): |
426 | 43 | """ | 116 | """ |
428 | 44 | The install hook installs the required packages. | 117 | The C{install_packages} method installs the required packages. |
429 | 45 | """ | 118 | """ |
430 | 46 | self.hookenv.config()["source"] = "ppa:landscape/14.10" | 119 | self.hookenv.config()["source"] = "ppa:landscape/14.10" |
432 | 47 | self.assertEqual(0, self.hook()) | 120 | self.apt.install_packages() |
433 | 48 | self.assertEqual([PACKAGES], self.fetch.filtered) | 121 | self.assertEqual([PACKAGES], self.fetch.filtered) |
435 | 49 | self.assertEqual([(PACKAGES, True)], self.fetch.installed) | 122 | options = list(DEFAULT_INSTALL_OPTIONS) |
436 | 123 | self.assertEqual([(PACKAGES, options, True)], self.fetch.installed) | ||
437 | 124 | |||
438 | 125 | def test_install_with_local_tarball(self): | ||
439 | 126 | """ | ||
440 | 127 | The C{install_packages} method allows unauthenticated packages if we | ||
441 | 128 | have a locally built repository. | ||
442 | 129 | """ | ||
443 | 130 | tarball = os.path.join( | ||
444 | 131 | self.hookenv.charm_dir(), "landscape-server_1.2.3.tar.gz") | ||
445 | 132 | with open(tarball, "w") as fd: | ||
446 | 133 | fd.write("") | ||
447 | 134 | self.hookenv.config()["source"] = "ppa:landscape/14.10" | ||
448 | 135 | self.apt.install_packages() | ||
449 | 136 | options = list(DEFAULT_INSTALL_OPTIONS) + ["--allow-unauthenticated"] | ||
450 | 137 | self.assertEqual([(PACKAGES, options, True)], self.fetch.installed) | ||
451 | 50 | 138 | ||
452 | === added file 'hooks/lib/tests/test_config.py' | |||
453 | --- hooks/lib/tests/test_config.py 1970-01-01 00:00:00 +0000 | |||
454 | +++ hooks/lib/tests/test_config.py 2015-03-09 11:56:41 +0000 | |||
455 | @@ -0,0 +1,25 @@ | |||
456 | 1 | from lib.tests.helpers import HookenvTest | ||
457 | 2 | from lib.tests.stubs import FetchStub, SubprocessStub | ||
458 | 3 | from lib.config import ConfigHook | ||
459 | 4 | |||
460 | 5 | |||
461 | 6 | class ConfigHookTest(HookenvTest): | ||
462 | 7 | |||
463 | 8 | def setUp(self): | ||
464 | 9 | super(ConfigHookTest, self).setUp() | ||
465 | 10 | self.fetch = FetchStub() | ||
466 | 11 | self.subprocess = SubprocessStub() | ||
467 | 12 | self.hook = ConfigHook( | ||
468 | 13 | hookenv=self.hookenv, fetch=self.fetch, subprocess=self.subprocess) | ||
469 | 14 | |||
470 | 15 | def test_run(self): | ||
471 | 16 | """ | ||
472 | 17 | The L{ConfigHook} re-configures APT sources if the have changed. | ||
473 | 18 | """ | ||
474 | 19 | config = self.hookenv.config() | ||
475 | 20 | config["source"] = "ppa:landscape/14.10" | ||
476 | 21 | config.save() | ||
477 | 22 | config.load_previous() | ||
478 | 23 | config["source"] = "ppa:landscape/15.01" | ||
479 | 24 | self.assertEqual(0, self.hook()) | ||
480 | 25 | self.assertTrue(len(self.fetch.sources) > 0) | ||
481 | 0 | 26 | ||
482 | === added file 'hooks/lib/tests/test_install.py' | |||
483 | --- hooks/lib/tests/test_install.py 1970-01-01 00:00:00 +0000 | |||
484 | +++ hooks/lib/tests/test_install.py 2015-03-09 11:56:41 +0000 | |||
485 | @@ -0,0 +1,23 @@ | |||
486 | 1 | from lib.tests.helpers import HookenvTest | ||
487 | 2 | from lib.tests.stubs import FetchStub, SubprocessStub | ||
488 | 3 | from lib.install import InstallHook | ||
489 | 4 | |||
490 | 5 | |||
491 | 6 | class InstallHookTest(HookenvTest): | ||
492 | 7 | |||
493 | 8 | def setUp(self): | ||
494 | 9 | super(InstallHookTest, self).setUp() | ||
495 | 10 | self.fetch = FetchStub() | ||
496 | 11 | self.subprocess = SubprocessStub() | ||
497 | 12 | self.hook = InstallHook( | ||
498 | 13 | hookenv=self.hookenv, fetch=self.fetch, subprocess=self.subprocess) | ||
499 | 14 | |||
500 | 15 | def test_run(self): | ||
501 | 16 | """ | ||
502 | 17 | The L{InstallHook} configures APT sources and install the needed | ||
503 | 18 | packages. | ||
504 | 19 | """ | ||
505 | 20 | self.hookenv.config()["source"] = "ppa:landscape/14.10" | ||
506 | 21 | self.assertEqual(0, self.hook()) | ||
507 | 22 | self.assertNotEqual([], self.fetch.sources) | ||
508 | 23 | self.assertNotEqual([], self.fetch.installed) |
Command: make ci-test /ci.lscape. net/job/ latch-test/ 148/
Result: Success
Revno: 240
Branch: lp:~free.ekanayaka/landscape-charm/install-from-deb
Jenkins: https:/