Merge lp:~adam-collard/charms/precise/reviewboard/trunk into lp:charms/reviewboard
- Precise Pangolin (12.04)
- trunk
- Merge into trunk
Proposed by
Adam Collard
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 31 | ||||
Proposed branch: | lp:~adam-collard/charms/precise/reviewboard/trunk | ||||
Merge into: | lp:charms/reviewboard | ||||
Diff against target: |
655 lines (+551/-18) 4 files modified
Makefile (+12/-0) README.md (+1/-2) hooks/hooks.py (+24/-16) hooks/tests/test_hooks.py (+514/-0) |
||||
To merge this branch: | bzr merge lp:~adam-collard/charms/precise/reviewboard/trunk | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Charles Butler (community) | Approve | ||
Review via email: mp+224041@code.launchpad.net |
Commit message
Description of the change
This branch adds unit test coverage to all of the implemented hooks and fixes a couple of bugs:
1. Lack of apt update before apt install meant (with out of date image files) units failed to install python-setuptools and therefore easy_install failed.
2. Ordering of relating and config setting (relating first and then setting config) meant a theoretical bug with failing to setup apache site.
To post a comment you must log in.
- 31. By Adam Collard
-
Add test dependencies and setup target
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'Makefile' |
2 | --- Makefile 1970-01-01 00:00:00 +0000 |
3 | +++ Makefile 2014-06-29 13:52:25 +0000 |
4 | @@ -0,0 +1,12 @@ |
5 | +.PHONY: check test lint setup |
6 | + |
7 | +test: setup |
8 | + cd hooks; trial tests |
9 | + |
10 | +lint: |
11 | + flake8 --exclude=charmhelpers hooks/ |
12 | + |
13 | +check: test lint |
14 | + |
15 | +setup: |
16 | + @sudo apt-get install python-twisted-core python-django python-mock |
17 | |
18 | === modified file 'README.md' |
19 | --- README.md 2014-06-10 18:53:50 +0000 |
20 | +++ README.md 2014-06-29 13:52:25 +0000 |
21 | @@ -35,11 +35,10 @@ |
22 | |
23 | ## Known Limitations and Issues |
24 | |
25 | -* Add test coverage |
26 | -* Add configuration for setting up initial repositories? |
27 | * Add support for MySQL as a database backend. |
28 | * Switch package installation between `python-psycopg2` and `python-mysqldb`. |
29 | * Change configuration of rb-site command. |
30 | +* Add configuration for setting up initial repositories? |
31 | * Optionally allow relation to separate |
32 | [memcached](https://jujucharms.com/sidebar/search/precise/memcached/) |
33 | charm instead of using local memcached. |
34 | |
35 | === modified file 'hooks/hooks.py' |
36 | --- hooks/hooks.py 2014-06-11 18:52:18 +0000 |
37 | +++ hooks/hooks.py 2014-06-29 13:52:25 +0000 |
38 | @@ -7,7 +7,7 @@ |
39 | |
40 | import charmhelpers.core.hookenv as hookenv |
41 | from charmhelpers.core.host import service_restart, service_stop |
42 | -from charmhelpers.fetch import apt_install |
43 | +from charmhelpers.fetch import apt_install, apt_update |
44 | |
45 | |
46 | hooks = hookenv.Hooks() |
47 | @@ -42,7 +42,8 @@ |
48 | |
49 | |
50 | @contextmanager |
51 | -def django_environ(): |
52 | +def _django_environ(): |
53 | + """Context manager for setting up DJANGO_SETTINGS_MODULE.""" |
54 | cwd = os.getcwd() |
55 | config_dir = "/var/www/reviewboard/conf" |
56 | os.chdir(config_dir) |
57 | @@ -119,8 +120,9 @@ |
58 | @hooks.hook('db-relation-changed') |
59 | def db_relation_changed(): |
60 | if not is_rb_site_installed(): |
61 | - if install_rb_site(): |
62 | - configure_apache2() |
63 | + install_rb_site() |
64 | + if is_rb_site_installed(): |
65 | + configure_apache2() |
66 | |
67 | |
68 | @hooks.hook("website-relation-joined") |
69 | @@ -134,23 +136,24 @@ |
70 | def config_changed(): |
71 | config = hookenv.config() |
72 | if not is_rb_site_installed(): |
73 | - if install_rb_site(): |
74 | - configure_apache2() |
75 | - else: |
76 | - # Failed to install rb site for some reason, try again later. |
77 | - return |
78 | - if config["admin-password"]: |
79 | - with django_environ(): |
80 | + install_rb_site() |
81 | + if is_rb_site_installed(): |
82 | + configure_apache2() |
83 | + else: |
84 | + # Failed to install rb site for some reason, try again later. |
85 | + return |
86 | + if config.get("admin-password"): |
87 | + with _django_environ(): |
88 | from django.contrib.auth.management.commands import changepassword |
89 | command = changepassword.Command() |
90 | command._get_pass = lambda *args: config["admin-password"] |
91 | command.execute("admin") |
92 | - if config["host"]: |
93 | + if config.get("host"): |
94 | if config["host"] == "localhost": |
95 | host = hookenv.unit_get("public-address") |
96 | else: |
97 | host = config["host"] |
98 | - with django_environ(): |
99 | + with _django_environ(): |
100 | from django.contrib.sites.models import Site |
101 | cur_site = Site.objects.get_current() |
102 | cur_site.domain = host |
103 | @@ -159,6 +162,7 @@ |
104 | |
105 | @hooks.hook("install") |
106 | def install(): |
107 | + apt_update(fatal=True) |
108 | apt_install(["apache2-mpm-prefork", |
109 | "libapache2-mod-wsgi", |
110 | "python-setuptools", |
111 | @@ -166,7 +170,7 @@ |
112 | "memcached", |
113 | "python-memcache", |
114 | "patch", |
115 | - "python-psycopg2"]) |
116 | + "python-psycopg2"], fatal=True) |
117 | hookenv.log("Installing ReviewBoard") |
118 | subprocess.check_call(["easy_install", "ReviewBoard"]) |
119 | |
120 | @@ -183,8 +187,12 @@ |
121 | service_stop("apache2") |
122 | |
123 | |
124 | -if __name__ == '__main__': |
125 | +def main(argv): |
126 | try: |
127 | - hooks.execute(sys.argv) |
128 | + hooks.execute(argv) |
129 | except hookenv.UnregisteredHookError as e: |
130 | hookenv.log('Unknown hook {} - skipping.'.format(e)) |
131 | + |
132 | + |
133 | +if __name__ == '__main__': |
134 | + main(sys.argv) |
135 | |
136 | === added directory 'hooks/tests' |
137 | === added file 'hooks/tests/__init__.py' |
138 | === added file 'hooks/tests/test_hooks.py' |
139 | --- hooks/tests/test_hooks.py 1970-01-01 00:00:00 +0000 |
140 | +++ hooks/tests/test_hooks.py 2014-06-29 13:52:25 +0000 |
141 | @@ -0,0 +1,514 @@ |
142 | +from contextlib import contextmanager |
143 | +import unittest |
144 | + |
145 | +from django.conf import settings |
146 | +settings.configure() |
147 | + |
148 | +from mock import patch |
149 | + |
150 | +import hooks |
151 | + |
152 | + |
153 | +class IsPostgresAvailableTest(unittest.TestCase): |
154 | + |
155 | + def setUp(self): |
156 | + super(IsPostgresAvailableTest, self).setUp() |
157 | + log_patcher = patch("charmhelpers.core.hookenv.log") |
158 | + self.mock_log = log_patcher.start() |
159 | + self.addCleanup(log_patcher.stop) |
160 | + |
161 | + @patch('charmhelpers.core.hookenv.is_relation_made') |
162 | + def test_requires_relation_to_db(self, mock_is_relation_made): |
163 | + """is_postgres_available depends on relation to PostgreSQL.""" |
164 | + mock_is_relation_made.return_value = False |
165 | + self.assertFalse(hooks.is_postgres_available()) |
166 | + mock_is_relation_made.assert_called_with("db") |
167 | + self.mock_log.assert_called_with("Missing relation to PostgreSQL") |
168 | + |
169 | + @patch('charmhelpers.core.hookenv.is_relation_made') |
170 | + @patch('charmhelpers.core.hookenv.local_unit') |
171 | + @patch('charmhelpers.core.hookenv.relation_get') |
172 | + def test_requires_unit_in_allowed_units( |
173 | + self, mock_relation_get, mock_local_unit, mock_is_relation_made): |
174 | + """is_postgres_available checks if unit is in allowed-units.""" |
175 | + mock_is_relation_made.return_value = True |
176 | + mock_local_unit.return_value = "test-unit/0" |
177 | + mock_relation_get.return_value = "another-unit/0" |
178 | + self.assertFalse(hooks.is_postgres_available()) |
179 | + self.mock_log.assert_called_with( |
180 | + "Unit is not yet allowed (another-unit/0)") |
181 | + |
182 | + @patch('charmhelpers.core.hookenv.is_relation_made') |
183 | + @patch('charmhelpers.core.hookenv.local_unit') |
184 | + @patch('charmhelpers.core.hookenv.relation_get') |
185 | + def test_checks_database_name( |
186 | + self, mock_relation_get, mock_local_unit, mock_is_relation_made): |
187 | + """If we are an allowed_unit then check the database name""" |
188 | + |
189 | + def relation_get_side_effect(relation_key): |
190 | + if relation_key == "allowed-units": |
191 | + return "test-unit/0" |
192 | + elif relation_key == "database": |
193 | + return "not-reviewboard" |
194 | + else: |
195 | + assert False, "Unexpected relation key %s" % relation_key |
196 | + |
197 | + mock_is_relation_made.return_value = True |
198 | + mock_local_unit.return_value = "test-unit/0" |
199 | + mock_relation_get.side_effect = relation_get_side_effect |
200 | + self.assertFalse(hooks.is_postgres_available()) |
201 | + self.mock_log.assert_called_with( |
202 | + "Database provided by PostgreSQL is " |
203 | + "not 'reviewboard': 'not-reviewboard'") |
204 | + |
205 | + @patch('charmhelpers.core.hookenv.is_relation_made') |
206 | + @patch('charmhelpers.core.hookenv.local_unit') |
207 | + @patch('charmhelpers.core.hookenv.relation_get') |
208 | + def test_everything_green( |
209 | + self, mock_relation_get, mock_local_unit, mock_is_relation_made): |
210 | + """When everything is OK, is_postgres_available returns True""" |
211 | + def relation_get_side_effect(relation_key): |
212 | + if relation_key == "allowed-units": |
213 | + return "test-unit/0" |
214 | + elif relation_key == "database": |
215 | + return "reviewboard" |
216 | + else: |
217 | + assert False, "Unexpected relation key %s" % relation_key |
218 | + |
219 | + mock_is_relation_made.return_value = True |
220 | + mock_local_unit.return_value = "test-unit/0" |
221 | + mock_relation_get.side_effect = relation_get_side_effect |
222 | + self.assertTrue(hooks.is_postgres_available()) |
223 | + self.assertFalse(self.mock_log.called) |
224 | + |
225 | + |
226 | +class IsRbSiteInstalledTest(unittest.TestCase): |
227 | + |
228 | + @patch("os.path.exists") |
229 | + def test_looks_for_site_directory(self, mock_exists): |
230 | + mock_exists.return_value = False |
231 | + self.assertFalse(hooks.is_rb_site_installed()) |
232 | + mock_exists.assert_called_with("/var/www/reviewboard") |
233 | + mock_exists.return_value = True |
234 | + self.assertTrue(hooks.is_rb_site_installed()) |
235 | + |
236 | + |
237 | +class InstallRbSiteTest(unittest.TestCase): |
238 | + |
239 | + def setUp(self): |
240 | + super(InstallRbSiteTest, self).setUp() |
241 | + config_patcher = patch("charmhelpers.core.hookenv.config") |
242 | + self.mock_config = config_patcher.start() |
243 | + self.addCleanup(config_patcher.stop) |
244 | + |
245 | + log_patcher = patch("charmhelpers.core.hookenv.log") |
246 | + self.mock_log = log_patcher.start() |
247 | + self.addCleanup(log_patcher.stop) |
248 | + |
249 | + available_patcher = patch("hooks.is_postgres_available") |
250 | + self.mock_available = available_patcher.start() |
251 | + self.mock_available.return_value = True |
252 | + self.addCleanup(available_patcher.stop) |
253 | + |
254 | + def test_guarded_on_is_postgres_available(self): |
255 | + self.mock_available.return_value = False |
256 | + self.assertFalse(hooks.install_rb_site()) |
257 | + self.mock_available.assert_called_with() |
258 | + |
259 | + def test_guarded_on_admin_password(self): |
260 | + self.mock_config.return_value = {} |
261 | + self.assertFalse(hooks.install_rb_site()) |
262 | + self.mock_log.assert_called_with( |
263 | + "admin-password is not set, refusing to configure site") |
264 | + |
265 | + @patch('charmhelpers.core.hookenv.unit_get') |
266 | + @patch('charmhelpers.core.hookenv.relation_get') |
267 | + @patch('subprocess.check_call') |
268 | + def test_host_info_from_config_defaults_to_public_address( |
269 | + self, mock_call, mock_relation_get, mock_unit_get): |
270 | + """ |
271 | + The host information is a config value which defaults to |
272 | + "localhost". When it is "localhost" that means use the public |
273 | + address of the unit. |
274 | + """ |
275 | + self.mock_config.return_value = {"admin-password": "a-password"} |
276 | + mock_unit_get.return_value = "8.8.8.8" |
277 | + mock_relation_get.return_value = {"host": "psql.example.com", |
278 | + "port": "5432", |
279 | + "user": "rb-db-user", |
280 | + "password": "hunter2"} |
281 | + self.assertTrue(hooks.install_rb_site()) |
282 | + args_list, kwargs_list = mock_call.call_args |
283 | + self.assertIn("--domain-name=8.8.8.8", args_list[0]) |
284 | + self.mock_log.assert_any_call( |
285 | + "Installing rb-site for 8.8.8.8 in /var/www/reviewboard") |
286 | + |
287 | + @patch('charmhelpers.core.hookenv.unit_get') |
288 | + @patch('charmhelpers.core.hookenv.relation_get') |
289 | + @patch('subprocess.check_call') |
290 | + def test_db_host_and_port_used_from_relation( |
291 | + self, mock_call, mock_relation_get, mock_unit_get): |
292 | + self.mock_config.return_value = {"admin-password": "a-password", |
293 | + "host": "rb.example.com"} |
294 | + mock_relation_get.return_value = {"host": "psql.example.com", |
295 | + "port": "5432", |
296 | + "user": "rb-db-user", |
297 | + "password": "hunter2"} |
298 | + self.assertTrue(hooks.install_rb_site()) |
299 | + args_list, kwargs_list = mock_call.call_args |
300 | + self.assertIn("--db-host=psql.example.com:5432", args_list[0]) |
301 | + |
302 | + @patch('charmhelpers.core.hookenv.unit_get') |
303 | + @patch('charmhelpers.core.hookenv.relation_get') |
304 | + @patch('subprocess.check_call') |
305 | + def test_db_user_used_from_relation( |
306 | + self, mock_call, mock_relation_get, mock_unit_get): |
307 | + self.mock_config.return_value = {"admin-password": "a-password", |
308 | + "host": "rb.example.com"} |
309 | + mock_relation_get.return_value = {"host": "psql.example.com", |
310 | + "port": "5432", |
311 | + "user": "rb-db-user", |
312 | + "password": "hunter2"} |
313 | + self.assertTrue(hooks.install_rb_site()) |
314 | + args_list, kwargs_list = mock_call.call_args |
315 | + self.assertIn("--db-user=rb-db-user", args_list[0]) |
316 | + |
317 | + @patch('charmhelpers.core.hookenv.unit_get') |
318 | + @patch('charmhelpers.core.hookenv.relation_get') |
319 | + @patch('subprocess.check_call') |
320 | + def test_db_password_used_from_relation( |
321 | + self, mock_call, mock_relation_get, mock_unit_get): |
322 | + self.mock_config.return_value = {"admin-password": "a-password", |
323 | + "host": "rb.example.com"} |
324 | + mock_relation_get.return_value = {"host": "psql.example.com", |
325 | + "port": "5432", |
326 | + "user": "rb-db-user", |
327 | + "password": "hunter2"} |
328 | + self.assertTrue(hooks.install_rb_site()) |
329 | + args_list, kwargs_list = mock_call.call_args |
330 | + self.assertIn("--db-pass=hunter2", args_list[0]) |
331 | + |
332 | + @patch('charmhelpers.core.hookenv.unit_get') |
333 | + @patch('charmhelpers.core.hookenv.relation_get') |
334 | + @patch('subprocess.check_call') |
335 | + def test_admin_password_used_from_config( |
336 | + self, mock_call, mock_relation_get, mock_unit_get): |
337 | + self.mock_config.return_value = {"admin-password": "a-password", |
338 | + "host": "rb.example.com"} |
339 | + mock_relation_get.return_value = {"host": "psql.example.com", |
340 | + "port": "5432", |
341 | + "user": "rb-db-user", |
342 | + "password": "hunter2"} |
343 | + self.assertTrue(hooks.install_rb_site()) |
344 | + args_list, kwargs_list = mock_call.call_args |
345 | + self.assertIn("--admin-password=a-password", args_list[0]) |
346 | + |
347 | + @patch('charmhelpers.core.hookenv.unit_get') |
348 | + @patch('charmhelpers.core.hookenv.relation_get') |
349 | + @patch('subprocess.check_call') |
350 | + def test_log_confirmation( |
351 | + self, mock_call, mock_relation_get, mock_unit_get): |
352 | + self.mock_config.return_value = {"admin-password": "a-password", |
353 | + "host": "rb.example.com"} |
354 | + mock_relation_get.return_value = {"host": "psql.example.com", |
355 | + "port": "5432", |
356 | + "user": "rb-db-user", |
357 | + "password": "hunter2"} |
358 | + self.assertTrue(hooks.install_rb_site()) |
359 | + self.mock_log.assert_called_with("Installed rb-site!") |
360 | + |
361 | + @patch('charmhelpers.core.hookenv.unit_get') |
362 | + @patch('charmhelpers.core.hookenv.relation_get') |
363 | + @patch('subprocess.check_call') |
364 | + def test_full_rb_site_install_command( |
365 | + self, mock_call, mock_relation_get, mock_unit_get): |
366 | + self.mock_config.return_value = {"admin-password": "a-password", |
367 | + "host": "rb.example.com"} |
368 | + mock_relation_get.return_value = {"host": "psql.example.com", |
369 | + "port": "5432", |
370 | + "user": "rb-db-user", |
371 | + "password": "hunter2"} |
372 | + self.assertTrue(hooks.install_rb_site()) |
373 | + args_list, kwargs_list = mock_call.call_args |
374 | + full_command_args = [ |
375 | + "rb-site", |
376 | + "install", |
377 | + "--noinput", |
378 | + "--domain-name=rb.example.com", |
379 | + "--db-type=postgresql", |
380 | + "--db-name=reviewboard", |
381 | + "--db-host=psql.example.com:5432", |
382 | + "--db-user=rb-db-user", |
383 | + "--db-pass=hunter2", |
384 | + "--cache-type=memcached", |
385 | + "--web-server-type=apache", |
386 | + "--web-server-port=80", |
387 | + "--python-loader=wsgi", |
388 | + "--admin-user=admin", |
389 | + "--admin-password=a-password", |
390 | + "/var/www/reviewboard"] |
391 | + |
392 | + self.assertEqual(full_command_args, args_list[0]) |
393 | + |
394 | + |
395 | +class ConfigureApache2Test(unittest.TestCase): |
396 | + |
397 | + def setUp(self): |
398 | + super(ConfigureApache2Test, self).setUp() |
399 | + log_patcher = patch("charmhelpers.core.hookenv.log") |
400 | + self.mock_log = log_patcher.start() |
401 | + self.addCleanup(log_patcher.stop) |
402 | + |
403 | + call_patcher = patch("subprocess.check_call") |
404 | + self.mock_call = call_patcher.start() |
405 | + self.addCleanup(call_patcher.stop) |
406 | + |
407 | + restart_patcher = patch("hooks.service_restart") |
408 | + self.mock_restart = restart_patcher.start() |
409 | + self.addCleanup(restart_patcher.stop) |
410 | + |
411 | + def test_copies_wsgi_conf(self): |
412 | + hooks.configure_apache2() |
413 | + self.mock_call.assert_any_call( |
414 | + ["cp", "/var/www/reviewboard/conf/apache-wsgi.conf", |
415 | + "/etc/apache2/sites-available/reviewboard.conf"]) |
416 | + |
417 | + def test_disables_default_site(self): |
418 | + hooks.configure_apache2() |
419 | + self.mock_call.assert_any_call(["a2dissite", "000-default"]) |
420 | + |
421 | + def test_enables_reviewboard_site(self): |
422 | + hooks.configure_apache2() |
423 | + self.mock_call.assert_any_call(["a2ensite", "reviewboard.conf"]) |
424 | + |
425 | + def test_chowns_dirs(self): |
426 | + hooks.configure_apache2() |
427 | + for leaf in ["htdocs/media/uploaded", "htdocs/media/ext", |
428 | + "htdocs/static/ext", "data"]: |
429 | + self.mock_call.assert_any_call( |
430 | + ["chown", "-R", "www-data", "/var/www/reviewboard/%s" % leaf]) |
431 | + |
432 | + def test_restarts_apache2(self): |
433 | + hooks.configure_apache2() |
434 | + self.mock_restart.assert_called_with("apache2") |
435 | + |
436 | + def test_log_confirmation(self): |
437 | + hooks.configure_apache2() |
438 | + self.mock_log.assert_called_with("Apache configured!") |
439 | + self.mock_log.assert_any_call("Configuring Apache...") |
440 | + |
441 | + |
442 | +class DbRelationJoinedTest(unittest.TestCase): |
443 | + |
444 | + @patch('charmhelpers.core.hookenv.relation_set') |
445 | + def test_requests_database(self, mock_relation_set): |
446 | + hooks.db_relation_joined() |
447 | + mock_relation_set.assert_called_with( |
448 | + relation_settings={"database": "reviewboard"}) |
449 | + |
450 | + |
451 | +class DbRelationChangedTest(unittest.TestCase): |
452 | + |
453 | + @patch('hooks.is_rb_site_installed') |
454 | + @patch('hooks.install_rb_site') |
455 | + @patch('hooks.configure_apache2') |
456 | + def test_configures_apache2_if_rb_needs_installing( |
457 | + self, mock_configure, mock_install, mock_installed): |
458 | + |
459 | + def mock_installed_side_effect(): |
460 | + mock_installed.side_effect = lambda: True |
461 | + return False |
462 | + |
463 | + mock_installed.side_effect = mock_installed_side_effect |
464 | + mock_install.return_value = True |
465 | + hooks.db_relation_changed() |
466 | + mock_install.assert_called_with() |
467 | + mock_configure.assert_called_with() |
468 | + |
469 | + @patch('hooks.is_rb_site_installed') |
470 | + @patch('hooks.configure_apache2') |
471 | + def test_configures_apache2_if_rb_already_installed( |
472 | + self, mock_configure, mock_installed): |
473 | + mock_installed.return_value = True |
474 | + hooks.db_relation_changed() |
475 | + mock_configure.assert_called_with() |
476 | + |
477 | + |
478 | +class WebsiteRelationJoinedTest(unittest.TestCase): |
479 | + |
480 | + @patch('charmhelpers.core.hookenv.unit_get') |
481 | + @patch('charmhelpers.core.hookenv.relation_set') |
482 | + def test_requests_database(self, mock_relation_set, mock_unit_get): |
483 | + mock_unit_get.return_value = "127.0.0.1" |
484 | + hooks.website_relation_joined() |
485 | + mock_relation_set.assert_called_with( |
486 | + relation_settings={"hostname": "127.0.0.1", "port": 80}) |
487 | + |
488 | + |
489 | +class ConfigChangedTest(unittest.TestCase): |
490 | + |
491 | + def setUp(self): |
492 | + super(ConfigChangedTest, self).setUp() |
493 | + config_patcher = patch("charmhelpers.core.hookenv.config") |
494 | + self.mock_config = config_patcher.start() |
495 | + self.mock_config.return_value = {} |
496 | + self.addCleanup(config_patcher.stop) |
497 | + |
498 | + @contextmanager |
499 | + def _fake_django_environ(): |
500 | + yield |
501 | + |
502 | + @patch('hooks.is_rb_site_installed') |
503 | + @patch('hooks.install_rb_site') |
504 | + @patch('hooks.configure_apache2') |
505 | + def test_configures_apache2_if_rb_needs_installing( |
506 | + self, mock_configure, mock_install, mock_installed): |
507 | + |
508 | + def mock_installed_side_effect(): |
509 | + mock_installed.side_effect = lambda: True |
510 | + return False |
511 | + |
512 | + mock_installed.side_effect = mock_installed_side_effect |
513 | + mock_install.return_value = True |
514 | + hooks.config_changed() |
515 | + mock_install.assert_called_with() |
516 | + mock_configure.assert_called_with() |
517 | + |
518 | + @patch('hooks.is_rb_site_installed') |
519 | + @patch('hooks.configure_apache2') |
520 | + def test_configures_apache2_if_rb_already_installed( |
521 | + self, mock_configure, mock_installed): |
522 | + mock_installed.return_value = True |
523 | + hooks.config_changed() |
524 | + mock_configure.assert_called_with() |
525 | + |
526 | + @patch('hooks.is_rb_site_installed') |
527 | + @patch('hooks.configure_apache2') |
528 | + @patch('hooks._django_environ', _fake_django_environ) |
529 | + @patch("django.contrib.auth.management.commands.changepassword.Command") |
530 | + def test_changes_password_for_admin_user( |
531 | + self, mock_command, mock_configure, mock_installed): |
532 | + mock_installed.return_value = True |
533 | + self.mock_config.return_value = {"admin-password": "a-password"} |
534 | + instance = mock_command.return_value |
535 | + hooks.config_changed() |
536 | + instance.execute.assert_called_with("admin") |
537 | + self.assertEqual(instance._get_pass(), "a-password") |
538 | + |
539 | + @patch('hooks.is_rb_site_installed') |
540 | + @patch('hooks.configure_apache2') |
541 | + @patch('hooks._django_environ', _fake_django_environ) |
542 | + @patch("django.contrib.sites.models.Site") |
543 | + def test_changes_host(self, mock_site, mock_configure, mock_installed): |
544 | + mock_installed.return_value = True |
545 | + self.mock_config.return_value = {"host": "rb.example.com"} |
546 | + instance = mock_site.objects.get_current.return_value |
547 | + hooks.config_changed() |
548 | + instance.save.assert_called_with() |
549 | + self.assertEqual(instance.domain, "rb.example.com") |
550 | + |
551 | + @patch('hooks.is_rb_site_installed') |
552 | + @patch('hooks.configure_apache2') |
553 | + @patch('charmhelpers.core.hookenv.unit_get') |
554 | + @patch('hooks._django_environ', _fake_django_environ) |
555 | + @patch("django.contrib.sites.models.Site") |
556 | + def test_localhost_means_public_address( |
557 | + self, mock_site, mock_unit_get, mock_configure, mock_installed): |
558 | + mock_installed.return_value = True |
559 | + self.mock_config.return_value = {"host": "localhost"} |
560 | + mock_unit_get.return_value = "8.8.8.8" |
561 | + instance = mock_site.objects.get_current.return_value |
562 | + hooks.config_changed() |
563 | + instance.save.assert_called_with() |
564 | + self.assertEqual(instance.domain, "8.8.8.8") |
565 | + |
566 | + |
567 | +class InstallTest(unittest.TestCase): |
568 | + |
569 | + def setUp(self): |
570 | + super(InstallTest, self).setUp() |
571 | + log_patcher = patch("charmhelpers.core.hookenv.log") |
572 | + self.mock_log = log_patcher.start() |
573 | + self.addCleanup(log_patcher.stop) |
574 | + |
575 | + update_patcher = patch("hooks.apt_update") |
576 | + self.mock_update = update_patcher.start() |
577 | + self.addCleanup(update_patcher.stop) |
578 | + |
579 | + install_patcher = patch("hooks.apt_install") |
580 | + self.mock_install = install_patcher.start() |
581 | + self.addCleanup(install_patcher.stop) |
582 | + |
583 | + call_patcher = patch("subprocess.check_call") |
584 | + self.mock_call = call_patcher.start() |
585 | + self.addCleanup(call_patcher.stop) |
586 | + |
587 | + def test_apt_packages(self): |
588 | + hooks.install() |
589 | + self.mock_install.assert_called_with( |
590 | + ["apache2-mpm-prefork", |
591 | + "libapache2-mod-wsgi", |
592 | + "python-setuptools", |
593 | + "python-dev", |
594 | + "memcached", |
595 | + "python-memcache", |
596 | + "patch", |
597 | + "python-psycopg2"], fatal=True) |
598 | + |
599 | + def test_apt_update(self): |
600 | + hooks.install() |
601 | + self.mock_update.assert_called_with(fatal=True) |
602 | + |
603 | + def test_easy_install(self): |
604 | + hooks.install() |
605 | + self.mock_call.assert_called_with(["easy_install", "ReviewBoard"]) |
606 | + |
607 | + def test_log(self): |
608 | + hooks.install() |
609 | + self.mock_log.assert_called_with("Installing ReviewBoard") |
610 | + |
611 | + |
612 | +class StartTest(unittest.TestCase): |
613 | + |
614 | + @patch("hooks.service_restart") |
615 | + @patch('charmhelpers.core.hookenv.open_port') |
616 | + def test_restarts_apache(self, mock_open_port, mock_restart): |
617 | + hooks.start() |
618 | + mock_restart.assert_called_with("apache2") |
619 | + |
620 | + @patch("hooks.service_restart") |
621 | + @patch('charmhelpers.core.hookenv.open_port') |
622 | + def test_opens_port_80(self, mock_open_port, mock_restart): |
623 | + hooks.start() |
624 | + mock_open_port.assert_called_with(80) |
625 | + |
626 | + |
627 | +class StopTest(unittest.TestCase): |
628 | + |
629 | + @patch("hooks.service_stop") |
630 | + @patch('charmhelpers.core.hookenv.close_port') |
631 | + def test_stops_apache(self, mock_close_port, mock_stop): |
632 | + hooks.stop() |
633 | + mock_stop.assert_called_with("apache2") |
634 | + |
635 | + @patch("hooks.service_stop") |
636 | + @patch('charmhelpers.core.hookenv.close_port') |
637 | + def test_closes_port_80(self, mock_close_port, mock_stop): |
638 | + hooks.stop() |
639 | + mock_close_port.assert_called_with(80) |
640 | + |
641 | + |
642 | +class MainTest(unittest.TestCase): |
643 | + |
644 | + @patch("hooks.hooks") |
645 | + def test_executes_sys_argv(self, mock_hooks): |
646 | + hooks.main(["arg", "v"]) |
647 | + mock_hooks.execute.assert_called_with(["arg", "v"]) |
648 | + |
649 | + @patch("hooks.hooks") |
650 | + @patch("charmhelpers.core.hookenv.log") |
651 | + def test_logs_about_unknown_hooks(self, mock_log, mock_hooks): |
652 | + mock_hooks.execute.side_effect =\ |
653 | + hooks.hookenv.UnregisteredHookError("missing-hook") |
654 | + hooks.main(["arg", "v"]) |
655 | + mock_log.assert_called_with("Unknown hook missing-hook - skipping.") |
Adam,
Thanks for the updated test suite and the make targets.
+1 LGTM