Merge lp:~gnuoy/charms/trusty/ceph-radosgw/unit-tests into lp:~openstack-charmers-archive/charms/trusty/ceph-radosgw/next
- Trusty Tahr (14.04)
- unit-tests
- Merge into next
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 36 | ||||
Proposed branch: | lp:~gnuoy/charms/trusty/ceph-radosgw/unit-tests | ||||
Merge into: | lp:~openstack-charmers-archive/charms/trusty/ceph-radosgw/next | ||||
Diff against target: |
788 lines (+728/-2) 8 files modified
.bzrignore (+2/-0) .coveragerc (+7/-0) Makefile (+4/-1) hooks/utils.py (+3/-1) unit_tests/__init__.py (+3/-0) unit_tests/test_ceph.py (+197/-0) unit_tests/test_hooks.py (+393/-0) unit_tests/test_utils.py (+119/-0) |
||||
To merge this branch: | bzr merge lp:~gnuoy/charms/trusty/ceph-radosgw/unit-tests | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenStack Charmers | Pending | ||
Review via email: mp+249167@code.launchpad.net |
Commit message
Description of the change
uosci-testing-bot (uosci-testing-bot) wrote : | # |
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #1833 ceph-radosgw-next for gnuoy mp249167
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #1852 ceph-radosgw-next for gnuoy mp249167
AMULET FAIL: amulet-test failed
AMULET Results (max last 2 lines):
ERROR subprocess encountered error code 124
make: *** [test] Error 124
Full amulet test output: http://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #1664 ceph-radosgw-next for gnuoy mp249167
UNIT FAIL: unit-test failed
UNIT Results (max last 2 lines):
FAILED (errors=1)
make: *** [unit_test] Error 1
Full unit test output: http://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #1666 ceph-radosgw-next for gnuoy mp249167
UNIT OK: passed
- 37. By Liam Young
-
Hack to patch out implicit install of python-dns and subsequent import of dns.python that is triggered by importing utils
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #1947 ceph-radosgw-next for gnuoy mp249167
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #1737 ceph-radosgw-next for gnuoy mp249167
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #1888 ceph-radosgw-next for gnuoy mp249167
AMULET OK: passed
Build: http://
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2014-09-17 14:11:53 +0000 |
3 | +++ .bzrignore 2015-02-12 09:06:09 +0000 |
4 | @@ -1,3 +1,5 @@ |
5 | .project |
6 | .pydevproject |
7 | bin |
8 | +.coveragerc |
9 | +.coverage |
10 | |
11 | === added file '.coveragerc' |
12 | --- .coveragerc 1970-01-01 00:00:00 +0000 |
13 | +++ .coveragerc 2015-02-12 09:06:09 +0000 |
14 | @@ -0,0 +1,7 @@ |
15 | +[report] |
16 | +# Regexes for lines to exclude from consideration |
17 | +exclude_lines = |
18 | + if __name__ == .__main__.: |
19 | +include= |
20 | + hooks/ceph.py |
21 | + hooks/hooks.py |
22 | |
23 | === modified file 'Makefile' |
24 | --- Makefile 2014-09-29 01:57:43 +0000 |
25 | +++ Makefile 2015-02-12 09:06:09 +0000 |
26 | @@ -2,9 +2,12 @@ |
27 | PYTHON := /usr/bin/env python |
28 | |
29 | lint: |
30 | - @flake8 --exclude hooks/charmhelpers hooks tests |
31 | + @flake8 --exclude hooks/charmhelpers hooks tests unit_tests |
32 | @charm proof |
33 | |
34 | +unit_test: |
35 | + @$(PYTHON) /usr/bin/nosetests --nologcapture --with-coverage unit_tests |
36 | + |
37 | test: |
38 | @echo Starting Amulet tests... |
39 | # coreycb note: The -v should only be temporary until Amulet sends |
40 | |
41 | === modified file 'hooks/utils.py' |
42 | --- hooks/utils.py 2015-01-15 16:18:33 +0000 |
43 | +++ hooks/utils.py 2015-02-12 09:06:09 +0000 |
44 | @@ -83,8 +83,10 @@ |
45 | sources.write(line) |
46 | |
47 | |
48 | -def get_host_ip(hostname=unit_get('private-address')): |
49 | +def get_host_ip(hostname=None): |
50 | try: |
51 | + if not hostname: |
52 | + hostname = unit_get('private-address') |
53 | # Test to see if already an IPv4 address |
54 | socket.inet_aton(hostname) |
55 | return hostname |
56 | |
57 | === added directory 'unit_tests' |
58 | === added file 'unit_tests/__init__.py' |
59 | --- unit_tests/__init__.py 1970-01-01 00:00:00 +0000 |
60 | +++ unit_tests/__init__.py 2015-02-12 09:06:09 +0000 |
61 | @@ -0,0 +1,3 @@ |
62 | +import sys |
63 | + |
64 | +sys.path.append('hooks/') |
65 | |
66 | === added file 'unit_tests/test_ceph.py' |
67 | --- unit_tests/test_ceph.py 1970-01-01 00:00:00 +0000 |
68 | +++ unit_tests/test_ceph.py 2015-02-12 09:06:09 +0000 |
69 | @@ -0,0 +1,197 @@ |
70 | +from test_utils import CharmTestCase |
71 | + |
72 | +import ceph |
73 | + |
74 | +TO_PATCH = [ |
75 | + 'get_unit_hostname', |
76 | + 'os', |
77 | + 'subprocess', |
78 | + 'time', |
79 | +] |
80 | + |
81 | + |
82 | +class CephRadosGWCephTests(CharmTestCase): |
83 | + |
84 | + def setUp(self): |
85 | + super(CephRadosGWCephTests, self).setUp(ceph, TO_PATCH) |
86 | + |
87 | + def test_is_quorum_leader(self): |
88 | + self.os.path.exists.return_value = True |
89 | + self.get_unit_hostname.return_value = 'myhost' |
90 | + self.subprocess.check_output.return_value = '{"state": "leader"}' |
91 | + self.assertEqual(ceph.is_quorum(), True) |
92 | + |
93 | + def test_is_quorum_notleader(self): |
94 | + self.os.path.exists.return_value = True |
95 | + self.get_unit_hostname.return_value = 'myhost' |
96 | + self.subprocess.check_output.return_value = '{"state": "notleader"}' |
97 | + self.assertEqual(ceph.is_quorum(), False) |
98 | + |
99 | + def test_is_quorum_valerror(self): |
100 | + self.os.path.exists.return_value = True |
101 | + self.get_unit_hostname.return_value = 'myhost' |
102 | + self.subprocess.check_output.return_value = "'state': 'bob'}" |
103 | + self.assertEqual(ceph.is_quorum(), False) |
104 | + |
105 | + def test_is_quorum_no_asok(self): |
106 | + self.os.path.exists.return_value = False |
107 | + self.assertEqual(ceph.is_quorum(), False) |
108 | + |
109 | + def test_is_leader(self): |
110 | + self.get_unit_hostname.return_value = 'myhost' |
111 | + self.os.path.exists.return_value = True |
112 | + self.subprocess.check_output.return_value = '{"state": "leader"}' |
113 | + self.assertEqual(ceph.is_leader(), True) |
114 | + |
115 | + def test_is_leader_notleader(self): |
116 | + self.get_unit_hostname.return_value = 'myhost' |
117 | + self.os.path.exists.return_value = True |
118 | + self.subprocess.check_output.return_value = '{"state": "notleader"}' |
119 | + self.assertEqual(ceph.is_leader(), False) |
120 | + |
121 | + def test_is_leader_valerror(self): |
122 | + self.get_unit_hostname.return_value = 'myhost' |
123 | + self.os.path.exists.return_value = True |
124 | + self.subprocess.check_output.return_value = "'state': 'bob'}" |
125 | + self.assertEqual(ceph.is_leader(), False) |
126 | + |
127 | + def test_is_leader_noasok(self): |
128 | + self.get_unit_hostname.return_value = 'myhost' |
129 | + self.os.path.exists.return_value = False |
130 | + self.assertEqual(ceph.is_leader(), False) |
131 | + |
132 | + def test_wait_for_quorum_yes(self): |
133 | + results = [True, False] |
134 | + |
135 | + def quorum(): |
136 | + return results.pop() |
137 | + _is_quorum = self.patch('is_quorum') |
138 | + _is_quorum.side_effect = quorum |
139 | + ceph.wait_for_quorum() |
140 | + self.time.sleep.assert_called_with(3) |
141 | + |
142 | + def test_wait_for_quorum_no(self): |
143 | + _is_quorum = self.patch('is_quorum') |
144 | + _is_quorum.return_value = True |
145 | + ceph.wait_for_quorum() |
146 | + self.assertFalse(self.time.sleep.called) |
147 | + |
148 | + def test_wait_for_bootstrap(self): |
149 | + results = [True, False] |
150 | + |
151 | + def bootstrapped(): |
152 | + return results.pop() |
153 | + _is_bootstrapped = self.patch('is_bootstrapped') |
154 | + _is_bootstrapped.side_effect = bootstrapped |
155 | + ceph.wait_for_bootstrap() |
156 | + self.time.sleep.assert_called_with(3) |
157 | + |
158 | + def test_add_bootstrap_hint(self): |
159 | + self.get_unit_hostname.return_value = 'myhost' |
160 | + cmd = [ |
161 | + "ceph", |
162 | + "--admin-daemon", |
163 | + '/var/run/ceph/ceph-mon.myhost.asok', |
164 | + "add_bootstrap_peer_hint", |
165 | + 'mypeer' |
166 | + ] |
167 | + self.os.path.exists.return_value = True |
168 | + ceph.add_bootstrap_hint('mypeer') |
169 | + self.subprocess.call.assert_called_with(cmd) |
170 | + |
171 | + def test_add_bootstrap_hint_noasok(self): |
172 | + self.get_unit_hostname.return_value = 'myhost' |
173 | + self.os.path.exists.return_value = False |
174 | + ceph.add_bootstrap_hint('mypeer') |
175 | + self.assertFalse(self.subprocess.call.called) |
176 | + |
177 | + def test_is_osd_disk(self): |
178 | + # XXX Insert real sgdisk output |
179 | + self.subprocess.check_output.return_value = \ |
180 | + 'Partition GUID code: 4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D' |
181 | + self.assertEqual(ceph.is_osd_disk('/dev/fmd0'), True) |
182 | + |
183 | + def test_is_osd_disk_no(self): |
184 | + # XXX Insert real sgdisk output |
185 | + self.subprocess.check_output.return_value = \ |
186 | + 'Partition GUID code: 5FBD7E29-9D25-41B8-AFD0-062C0CEFF05D' |
187 | + self.assertEqual(ceph.is_osd_disk('/dev/fmd0'), False) |
188 | + |
189 | + def test_rescan_osd_devices(self): |
190 | + cmd = [ |
191 | + 'udevadm', 'trigger', |
192 | + '--subsystem-match=block', '--action=add' |
193 | + ] |
194 | + ceph.rescan_osd_devices() |
195 | + self.subprocess.call.assert_called_with(cmd) |
196 | + |
197 | + def test_zap_disk(self): |
198 | + cmd = [ |
199 | + 'sgdisk', '--zap-all', '/dev/fmd0', |
200 | + ] |
201 | + ceph.zap_disk('/dev/fmd0') |
202 | + self.subprocess.check_call.assert_called_with(cmd) |
203 | + |
204 | + def test_import_osd_bootstrap_key(self): |
205 | + self.os.path.exists.return_value = False |
206 | + cmd = [ |
207 | + 'ceph-authtool', |
208 | + '/var/lib/ceph/bootstrap-osd/ceph.keyring', |
209 | + '--create-keyring', |
210 | + '--name=client.bootstrap-osd', |
211 | + '--add-key=mykey', |
212 | + ] |
213 | + ceph.import_osd_bootstrap_key('mykey') |
214 | + self.subprocess.check_call.assert_called_with(cmd) |
215 | + |
216 | + def test_is_bootstrapped(self): |
217 | + self.os.path.exists.return_value = True |
218 | + self.assertEqual(ceph.is_bootstrapped(), True) |
219 | + self.os.path.exists.return_value = False |
220 | + self.assertEqual(ceph.is_bootstrapped(), False) |
221 | + |
222 | + def test_import_radosgw_key(self): |
223 | + self.os.path.exists.return_value = False |
224 | + ceph.import_radosgw_key('mykey') |
225 | + cmd = [ |
226 | + 'ceph-authtool', |
227 | + '/etc/ceph/keyring.rados.gateway', |
228 | + '--create-keyring', |
229 | + '--name=client.radosgw.gateway', |
230 | + '--add-key=mykey' |
231 | + ] |
232 | + self.subprocess.check_call.assert_called_with(cmd) |
233 | + |
234 | + def test_get_named_key_create(self): |
235 | + self.get_unit_hostname.return_value = "myhost" |
236 | + self.subprocess.check_output.return_value = """ |
237 | + |
238 | +[client.dummy] |
239 | + key = AQAPiu1RCMb4CxAAmP7rrufwZPRqy8bpQa2OeQ== |
240 | +""" |
241 | + self.assertEqual(ceph.get_named_key('dummy'), |
242 | + 'AQAPiu1RCMb4CxAAmP7rrufwZPRqy8bpQa2OeQ==') |
243 | + cmd = [ |
244 | + 'ceph', |
245 | + '--name', 'mon.', |
246 | + '--keyring', |
247 | + '/var/lib/ceph/mon/ceph-myhost/keyring', |
248 | + 'auth', 'get-or-create', 'client.dummy', |
249 | + 'mon', 'allow r', 'osd', 'allow rwx' |
250 | + ] |
251 | + self.subprocess.check_output.assert_called_with(cmd) |
252 | + |
253 | + def test_get_named_key_get(self): |
254 | + self.get_unit_hostname.return_value = "myhost" |
255 | + key = "AQAPiu1RCMb4CxAAmP7rrufwZPRqy8bpQa2OeQ==" |
256 | + self.subprocess.check_output.return_value = key |
257 | + self.assertEqual(ceph.get_named_key('dummy'), key) |
258 | + cmd = [ |
259 | + 'ceph', |
260 | + '--name', 'mon.', |
261 | + '--keyring', |
262 | + '/var/lib/ceph/mon/ceph-myhost/keyring', |
263 | + 'auth', 'get-or-create', 'client.dummy', |
264 | + 'mon', 'allow r', 'osd', 'allow rwx' |
265 | + ] |
266 | + self.subprocess.check_output.assert_called_with(cmd) |
267 | |
268 | === added file 'unit_tests/test_hooks.py' |
269 | --- unit_tests/test_hooks.py 1970-01-01 00:00:00 +0000 |
270 | +++ unit_tests/test_hooks.py 2015-02-12 09:06:09 +0000 |
271 | @@ -0,0 +1,393 @@ |
272 | + |
273 | +from mock import call, patch, MagicMock |
274 | +from test_utils import CharmTestCase, patch_open |
275 | + |
276 | +dnsmock = MagicMock() |
277 | +modules = { |
278 | + 'dns': dnsmock, |
279 | + 'dns.resolver': dnsmock, |
280 | +} |
281 | +module_patcher = patch.dict('sys.modules', modules) |
282 | +module_patcher.start() |
283 | +with patch('charmhelpers.fetch.apt_install'): |
284 | + import utils |
285 | + |
286 | +_reg = utils.register_configs |
287 | + |
288 | +utils.register_configs = MagicMock() |
289 | + |
290 | +import hooks as ceph_hooks |
291 | + |
292 | +utils.register_configs = _reg |
293 | + |
294 | +TO_PATCH = [ |
295 | + 'add_source', |
296 | + 'apt_update', |
297 | + 'apt_install', |
298 | + 'apt_purge', |
299 | + 'config', |
300 | + 'cmp_pkgrevno', |
301 | + 'execd_preinstall', |
302 | + 'enable_pocket', |
303 | + 'get_host_ip', |
304 | + 'get_iface_for_address', |
305 | + 'get_netmask_for_address', |
306 | + 'get_unit_hostname', |
307 | + 'glob', |
308 | + 'is_apache_24', |
309 | + 'log', |
310 | + 'lsb_release', |
311 | + 'open_port', |
312 | + 'os', |
313 | + 'related_units', |
314 | + 'relation_ids', |
315 | + 'relation_set', |
316 | + 'relation_get', |
317 | + 'render_template', |
318 | + 'resolve_address', |
319 | + 'shutil', |
320 | + 'subprocess', |
321 | + 'sys', |
322 | + 'unit_get', |
323 | +] |
324 | + |
325 | + |
326 | +class CephRadosGWTests(CharmTestCase): |
327 | + |
328 | + def setUp(self): |
329 | + super(CephRadosGWTests, self).setUp(ceph_hooks, TO_PATCH) |
330 | + self.config.side_effect = self.test_config.get |
331 | + self.test_config.set('source', 'distro') |
332 | + self.test_config.set('key', 'secretkey') |
333 | + self.test_config.set('use-syslog', False) |
334 | + |
335 | + def test_install_www_scripts(self): |
336 | + self.glob.glob.return_value = ['files/www/bob'] |
337 | + ceph_hooks.install_www_scripts() |
338 | + self.shutil.copy.assert_called_with('files/www/bob', '/var/www/') |
339 | + |
340 | + def test_install_ceph_optimised_packages(self): |
341 | + self.lsb_release.return_value = {'DISTRIB_CODENAME': 'vivid'} |
342 | + fastcgi_source = ( |
343 | + 'http://gitbuilder.ceph.com/' |
344 | + 'libapache-mod-fastcgi-deb-vivid-x86_64-basic/ref/master') |
345 | + apache_source = ( |
346 | + 'http://gitbuilder.ceph.com/' |
347 | + 'apache2-deb-vivid-x86_64-basic/ref/master') |
348 | + calls = [ |
349 | + call(fastcgi_source, key='6EAEAE2203C3951A'), |
350 | + call(apache_source, key='6EAEAE2203C3951A'), |
351 | + ] |
352 | + ceph_hooks.install_ceph_optimised_packages() |
353 | + self.add_source.assert_has_calls(calls) |
354 | + |
355 | + def test_install_packages(self): |
356 | + self.test_config.set('use-ceph-optimised-packages', '') |
357 | + ceph_hooks.install_packages() |
358 | + self.add_source.assert_called_with('distro', 'secretkey') |
359 | + self.apt_update.assert_called() |
360 | + self.apt_install.assert_called_with(['libapache2-mod-fastcgi', |
361 | + 'apache2'], fatal=True) |
362 | + |
363 | + def test_install_optimised_packages_no_embedded(self): |
364 | + self.test_config.set('use-ceph-optimised-packages', True) |
365 | + self.test_config.set('use-embedded-webserver', False) |
366 | + _install_packages = self.patch('install_ceph_optimised_packages') |
367 | + ceph_hooks.install_packages() |
368 | + self.add_source.assert_called_with('distro', 'secretkey') |
369 | + self.apt_update.assert_called() |
370 | + _install_packages.assert_called() |
371 | + self.apt_install.assert_called_with(['libapache2-mod-fastcgi', |
372 | + 'apache2'], fatal=True) |
373 | + |
374 | + def test_install_optimised_packages_embedded(self): |
375 | + self.test_config.set('use-ceph-optimised-packages', True) |
376 | + self.test_config.set('use-embedded-webserver', True) |
377 | + _install_packages = self.patch('install_ceph_optimised_packages') |
378 | + ceph_hooks.install_packages() |
379 | + self.add_source.assert_called_with('distro', 'secretkey') |
380 | + self.apt_update.assert_called() |
381 | + _install_packages.assert_called() |
382 | + self.apt_install.assert_called_with(['radosgw', |
383 | + 'ntp', |
384 | + 'haproxy'], fatal=True) |
385 | + self.apt_purge.assert_called_with(['libapache2-mod-fastcgi', |
386 | + 'apache2']) |
387 | + |
388 | + def test_install(self): |
389 | + _install_packages = self.patch('install_packages') |
390 | + ceph_hooks.install() |
391 | + self.execd_preinstall.assert_called() |
392 | + _install_packages.assert_called() |
393 | + self.enable_pocket.assert_called_with('multiverse') |
394 | + self.os.makedirs.called_with('/var/lib/ceph/nss') |
395 | + |
396 | + def test_emit_cephconf(self): |
397 | + _get_keystone_conf = self.patch('get_keystone_conf') |
398 | + _get_auth = self.patch('get_auth') |
399 | + _get_mon_hosts = self.patch('get_mon_hosts') |
400 | + _get_auth.return_value = 'cephx' |
401 | + _get_keystone_conf.return_value = {'keystone_key': 'keystone_value'} |
402 | + _get_mon_hosts.return_value = ['10.0.0.1:6789', '10.0.0.2:6789'] |
403 | + self.get_unit_hostname.return_value = 'bob' |
404 | + self.os.path.exists.return_value = False |
405 | + cephcontext = { |
406 | + 'auth_supported': 'cephx', |
407 | + 'mon_hosts': '10.0.0.1:6789 10.0.0.2:6789', |
408 | + 'hostname': 'bob', |
409 | + 'old_auth': False, |
410 | + 'use_syslog': 'false', |
411 | + 'keystone_key': 'keystone_value', |
412 | + 'embedded_webserver': False, |
413 | + } |
414 | + self.cmp_pkgrevno.return_value = 1 |
415 | + with patch_open() as (_open, _file): |
416 | + ceph_hooks.emit_cephconf() |
417 | + self.os.makedirs.assert_called_with('/etc/ceph') |
418 | + _open.assert_called_with('/etc/ceph/ceph.conf', 'w') |
419 | + self.render_template.assert_called_with('ceph.conf', cephcontext) |
420 | + |
421 | + def test_emit_apacheconf(self): |
422 | + self.is_apache_24.return_value = True |
423 | + self.unit_get.return_value = '10.0.0.1' |
424 | + apachecontext = { |
425 | + "hostname": '10.0.0.1', |
426 | + } |
427 | + vhost_file = '/etc/apache2/sites-available/rgw.conf' |
428 | + with patch_open() as (_open, _file): |
429 | + ceph_hooks.emit_apacheconf() |
430 | + _open.assert_called_with(vhost_file, 'w') |
431 | + self.render_template.assert_called_with('rgw', apachecontext) |
432 | + |
433 | + def test_apache_sites24(self): |
434 | + self.is_apache_24.return_value = True |
435 | + ceph_hooks.apache_sites() |
436 | + calls = [ |
437 | + call(['a2dissite', '000-default']), |
438 | + call(['a2ensite', 'rgw']), |
439 | + ] |
440 | + self.subprocess.check_call.assert_has_calls(calls) |
441 | + |
442 | + def test_apache_sites22(self): |
443 | + self.is_apache_24.return_value = False |
444 | + ceph_hooks.apache_sites() |
445 | + calls = [ |
446 | + call(['a2dissite', 'default']), |
447 | + call(['a2ensite', 'rgw']), |
448 | + ] |
449 | + self.subprocess.check_call.assert_has_calls(calls) |
450 | + |
451 | + def test_apache_modules(self): |
452 | + ceph_hooks.apache_modules() |
453 | + calls = [ |
454 | + call(['a2enmod', 'fastcgi']), |
455 | + call(['a2enmod', 'rewrite']), |
456 | + ] |
457 | + self.subprocess.check_call.assert_has_calls(calls) |
458 | + |
459 | + def test_apache_reload(self): |
460 | + ceph_hooks.apache_reload() |
461 | + calls = [ |
462 | + call(['service', 'apache2', 'reload']), |
463 | + ] |
464 | + self.subprocess.call.assert_has_calls(calls) |
465 | + |
466 | + def test_config_changed(self): |
467 | + _install_packages = self.patch('install_packages') |
468 | + _emit_cephconf = self.patch('emit_cephconf') |
469 | + _emit_apacheconf = self.patch('emit_apacheconf') |
470 | + _install_www_scripts = self.patch('install_www_scripts') |
471 | + _apache_sites = self.patch('apache_sites') |
472 | + _apache_modules = self.patch('apache_modules') |
473 | + _apache_reload = self.patch('apache_reload') |
474 | + ceph_hooks.config_changed() |
475 | + _install_packages.assert_called() |
476 | + _emit_cephconf.assert_called() |
477 | + _emit_apacheconf.assert_called() |
478 | + _install_www_scripts.assert_called() |
479 | + _apache_sites.assert_called() |
480 | + _apache_modules.assert_called() |
481 | + _apache_reload.assert_called() |
482 | + |
483 | + def test_get_mon_hosts(self): |
484 | + self.relation_ids.return_value = ['monrelid'] |
485 | + self.related_units.return_value = ['monunit'] |
486 | + self.relation_get.return_value = '10.0.0.1' |
487 | + self.get_host_ip.return_value = '10.0.0.1' |
488 | + self.assertEquals(ceph_hooks.get_mon_hosts(), ['10.0.0.1:6789']) |
489 | + |
490 | + def test_get_conf(self): |
491 | + self.relation_ids.return_value = ['monrelid'] |
492 | + self.related_units.return_value = ['monunit'] |
493 | + self.relation_get.return_value = 'bob' |
494 | + self.assertEquals(ceph_hooks.get_conf('key'), 'bob') |
495 | + |
496 | + def test_get_conf_nomatch(self): |
497 | + self.relation_ids.return_value = ['monrelid'] |
498 | + self.related_units.return_value = ['monunit'] |
499 | + self.relation_get.return_value = '' |
500 | + self.assertEquals(ceph_hooks.get_conf('key'), None) |
501 | + |
502 | + def test_get_auth(self): |
503 | + self.relation_ids.return_value = ['monrelid'] |
504 | + self.related_units.return_value = ['monunit'] |
505 | + self.relation_get.return_value = 'bob' |
506 | + self.assertEquals(ceph_hooks.get_auth(), 'bob') |
507 | + |
508 | + def test_get_keystone_conf(self): |
509 | + self.test_config.set('operator-roles', 'admin') |
510 | + self.test_config.set('cache-size', '42') |
511 | + self.test_config.set('revocation-check-interval', '21') |
512 | + self.relation_ids.return_value = ['idrelid'] |
513 | + self.related_units.return_value = ['idunit'] |
514 | + |
515 | + def _relation_get(key, unit, relid): |
516 | + ks_dict = { |
517 | + 'auth_protocol': 'https', |
518 | + 'auth_host': '10.0.0.2', |
519 | + 'auth_port': '8090', |
520 | + 'admin_token': 'sectocken', |
521 | + } |
522 | + return ks_dict[key] |
523 | + self.relation_get.side_effect = _relation_get |
524 | + self.assertEquals(ceph_hooks.get_keystone_conf(), { |
525 | + 'auth_type': 'keystone', |
526 | + 'auth_protocol': 'https', |
527 | + 'admin_token': 'sectocken', |
528 | + 'user_roles': 'admin', |
529 | + 'auth_host': '10.0.0.2', |
530 | + 'cache_size': '42', |
531 | + 'auth_port': '8090', |
532 | + 'revocation_check_interval': '21'}) |
533 | + |
534 | + def test_get_keystone_conf_missinginfo(self): |
535 | + self.test_config.set('operator-roles', 'admin') |
536 | + self.test_config.set('cache-size', '42') |
537 | + self.test_config.set('revocation-check-interval', '21') |
538 | + self.relation_ids.return_value = ['idrelid'] |
539 | + self.related_units.return_value = ['idunit'] |
540 | + |
541 | + def _relation_get(key, unit, relid): |
542 | + ks_dict = { |
543 | + 'auth_protocol': 'https', |
544 | + 'auth_host': '10.0.0.2', |
545 | + 'auth_port': '8090', |
546 | + } |
547 | + return ks_dict[key] if key in ks_dict else None |
548 | + self.relation_get.side_effect = _relation_get |
549 | + self.assertEquals(ceph_hooks.get_keystone_conf(), None) |
550 | + |
551 | + def test_mon_relation(self): |
552 | + _emit_cephconf = self.patch('emit_cephconf') |
553 | + _ceph = self.patch('ceph') |
554 | + _restart = self.patch('restart') |
555 | + self.relation_get.return_value = 'seckey' |
556 | + ceph_hooks.mon_relation() |
557 | + _restart.assert_called() |
558 | + _ceph.import_radosgw_key.assert_called_with('seckey') |
559 | + _emit_cephconf.assert_called() |
560 | + |
561 | + def test_mon_relation_nokey(self): |
562 | + _emit_cephconf = self.patch('emit_cephconf') |
563 | + _ceph = self.patch('ceph') |
564 | + _restart = self.patch('restart') |
565 | + self.relation_get.return_value = None |
566 | + ceph_hooks.mon_relation() |
567 | + self.assertFalse(_ceph.import_radosgw_key.called) |
568 | + self.assertFalse(_restart.called) |
569 | + _emit_cephconf.assert_called() |
570 | + |
571 | + def test_gateway_relation(self): |
572 | + self.unit_get.return_value = 'myserver' |
573 | + ceph_hooks.gateway_relation() |
574 | + self.relation_set.assert_called_with(hostname='myserver', port=80) |
575 | + |
576 | + def test_start(self): |
577 | + ceph_hooks.start() |
578 | + cmd = ['service', 'radosgw', 'start'] |
579 | + self.subprocess.call.assert_called_with(cmd) |
580 | + |
581 | + def test_stop(self): |
582 | + ceph_hooks.stop() |
583 | + cmd = ['service', 'radosgw', 'stop'] |
584 | + self.subprocess.call.assert_called_with(cmd) |
585 | + |
586 | + def test_restart(self): |
587 | + ceph_hooks.restart() |
588 | + cmd = ['service', 'radosgw', 'restart'] |
589 | + self.subprocess.call.assert_called_with(cmd) |
590 | + |
591 | + def test_identity_joined_early_version(self): |
592 | + self.cmp_pkgrevno.return_value = -1 |
593 | + ceph_hooks.identity_joined() |
594 | + self.sys.exit.assert_called_with(1) |
595 | + |
596 | + def test_identity_joined(self): |
597 | + self.cmp_pkgrevno.return_value = 1 |
598 | + self.resolve_address.return_value = 'myserv' |
599 | + self.test_config.set('region', 'region1') |
600 | + self.test_config.set('operator-roles', 'admin') |
601 | + self.unit_get.return_value = 'myserv' |
602 | + ceph_hooks.identity_joined(relid='rid') |
603 | + self.relation_set.assert_called_with( |
604 | + service='swift', |
605 | + region='region1', |
606 | + public_url='http://myserv:80/swift/v1', |
607 | + internal_url='http://myserv:80/swift/v1', |
608 | + requested_roles='admin', |
609 | + relation_id='rid', |
610 | + admin_url='http://myserv:80/swift') |
611 | + |
612 | + def test_identity_changed(self): |
613 | + _emit_cephconf = self.patch('emit_cephconf') |
614 | + _restart = self.patch('restart') |
615 | + ceph_hooks.identity_changed() |
616 | + _emit_cephconf.assert_called() |
617 | + _restart.assert_called() |
618 | + |
619 | + def test_canonical_url_ipv6(self): |
620 | + ipv6_addr = '2001:db8:85a3:8d3:1319:8a2e:370:7348' |
621 | + self.resolve_address.return_value = ipv6_addr |
622 | + self.assertEquals(ceph_hooks.canonical_url({}), |
623 | + 'http://[%s]' % ipv6_addr) |
624 | + |
625 | + @patch.object(ceph_hooks, 'CONFIGS') |
626 | + def test_cluster_changed(self, configs): |
627 | + _id_joined = self.patch('identity_joined') |
628 | + self.relation_ids.return_value = ['rid'] |
629 | + ceph_hooks.cluster_changed() |
630 | + configs.write_all.assert_called() |
631 | + _id_joined.assert_called_with(relid='rid') |
632 | + |
633 | + def test_ha_relation_joined_no_vip(self): |
634 | + self.test_config.set('vip', '') |
635 | + ceph_hooks.ha_relation_joined() |
636 | + self.sys.exit.assert_called_with(1) |
637 | + |
638 | + def test_ha_relation_joined_vip(self): |
639 | + self.test_config.set('ha-bindiface', 'eth8') |
640 | + self.test_config.set('ha-mcastport', '5000') |
641 | + self.test_config.set('vip', '10.0.0.10') |
642 | + self.get_iface_for_address.return_value = 'eth7' |
643 | + self.get_netmask_for_address.return_value = '255.255.0.0' |
644 | + ceph_hooks.ha_relation_joined() |
645 | + eth_params = ('params ip="10.0.0.10" cidr_netmask="255.255.0.0" ' |
646 | + 'nic="eth7"') |
647 | + resources = {'res_cephrg_haproxy': 'lsb:haproxy', |
648 | + 'res_cephrg_eth7_vip': 'ocf:heartbeat:IPaddr2'} |
649 | + resource_params = {'res_cephrg_haproxy': 'op monitor interval="5s"', |
650 | + 'res_cephrg_eth7_vip': eth_params} |
651 | + self.relation_set.assert_called_with( |
652 | + init_services={'res_cephrg_haproxy': 'haproxy'}, |
653 | + corosync_bindiface='eth8', |
654 | + corosync_mcastport='5000', |
655 | + resource_params=resource_params, |
656 | + resources=resources, |
657 | + clones={'cl_cephrg_haproxy': 'res_cephrg_haproxy'}) |
658 | + |
659 | + def test_ha_relation_changed(self): |
660 | + _id_joined = self.patch('identity_joined') |
661 | + self.relation_get.return_value = True |
662 | + self.relation_ids.return_value = ['rid'] |
663 | + ceph_hooks.ha_relation_changed() |
664 | + _id_joined.assert_called_with(relid='rid') |
665 | |
666 | === added file 'unit_tests/test_utils.py' |
667 | --- unit_tests/test_utils.py 1970-01-01 00:00:00 +0000 |
668 | +++ unit_tests/test_utils.py 2015-02-12 09:06:09 +0000 |
669 | @@ -0,0 +1,119 @@ |
670 | +import logging |
671 | +import os |
672 | +import unittest |
673 | +import yaml |
674 | + |
675 | +from contextlib import contextmanager |
676 | +from mock import patch, MagicMock |
677 | + |
678 | + |
679 | +def load_config(): |
680 | + '''Walk backwords from __file__ looking for config.yaml, |
681 | + load and return the 'options' section' |
682 | + ''' |
683 | + config = None |
684 | + f = __file__ |
685 | + while config is None: |
686 | + d = os.path.dirname(f) |
687 | + if os.path.isfile(os.path.join(d, 'config.yaml')): |
688 | + config = os.path.join(d, 'config.yaml') |
689 | + break |
690 | + f = d |
691 | + |
692 | + if not config: |
693 | + logging.error('Could not find config.yaml in any parent directory ' |
694 | + 'of %s. ' % file) |
695 | + raise Exception |
696 | + |
697 | + return yaml.safe_load(open(config).read())['options'] |
698 | + |
699 | + |
700 | +def get_default_config(): |
701 | + '''Load default charm config from config.yaml return as a dict. |
702 | + If no default is set in config.yaml, its value is None. |
703 | + ''' |
704 | + default_config = {} |
705 | + config = load_config() |
706 | + for k, v in config.iteritems(): |
707 | + if 'default' in v: |
708 | + default_config[k] = v['default'] |
709 | + else: |
710 | + default_config[k] = None |
711 | + return default_config |
712 | + |
713 | + |
714 | +class CharmTestCase(unittest.TestCase): |
715 | + |
716 | + def setUp(self, obj, patches): |
717 | + super(CharmTestCase, self).setUp() |
718 | + self.patches = patches |
719 | + self.obj = obj |
720 | + self.test_config = TestConfig() |
721 | + self.test_relation = TestRelation() |
722 | + self.patch_all() |
723 | + |
724 | + def patch(self, method): |
725 | + _m = patch.object(self.obj, method) |
726 | + mock = _m.start() |
727 | + self.addCleanup(_m.stop) |
728 | + return mock |
729 | + |
730 | + def patch_all(self): |
731 | + for method in self.patches: |
732 | + setattr(self, method, self.patch(method)) |
733 | + |
734 | + |
735 | +class TestConfig(object): |
736 | + |
737 | + def __init__(self): |
738 | + self.config = get_default_config() |
739 | + |
740 | + def get(self, attr=None): |
741 | + if not attr: |
742 | + return self.get_all() |
743 | + try: |
744 | + return self.config[attr] |
745 | + except KeyError: |
746 | + return None |
747 | + |
748 | + def get_all(self): |
749 | + return self.config |
750 | + |
751 | + def set(self, attr, value): |
752 | + if attr not in self.config: |
753 | + raise KeyError |
754 | + self.config[attr] = value |
755 | + |
756 | + |
757 | +class TestRelation(object): |
758 | + |
759 | + def __init__(self, relation_data={}): |
760 | + self.relation_data = relation_data |
761 | + |
762 | + def set(self, relation_data): |
763 | + self.relation_data = relation_data |
764 | + |
765 | + def get(self, attr=None, unit=None, rid=None): |
766 | + if attr is None: |
767 | + return self.relation_data |
768 | + elif attr in self.relation_data: |
769 | + return self.relation_data[attr] |
770 | + return None |
771 | + |
772 | + |
773 | +@contextmanager |
774 | +def patch_open(): |
775 | + '''Patch open() to allow mocking both open() itself and the file that is |
776 | + yielded. |
777 | + Yields the mock for "open" and "file", respectively. |
778 | + ''' |
779 | + mock_open = MagicMock(spec=open) |
780 | + mock_file = MagicMock(spec=file) |
781 | + |
782 | + @contextmanager |
783 | + def stub_open(*args, **kwargs): |
784 | + mock_open(*args, **kwargs) |
785 | + yield mock_file |
786 | + |
787 | + with patch('__builtin__.open', stub_open): |
788 | + yield mock_open, mock_file |
charm_unit_test #1661 ceph-radosgw-next for gnuoy mp249167
UNIT FAIL: unit-test failed
UNIT Results (max last 2 lines):
FAILED (errors=1)
make: *** [unit_test] Error 1
Full unit test output: http:// paste.ubuntu. com/10156943/ 10.245. 162.77: 8080/job/ charm_unit_ test/1661/
Build: http://