Merge lp:~chris.macnaughton/charm-helpers/pids-can-be-a-list into lp:charm-helpers

Proposed by Chris MacNaughton
Status: Merged
Merged at revision: 562
Proposed branch: lp:~chris.macnaughton/charm-helpers/pids-can-be-a-list
Merge into: lp:charm-helpers
Diff against target: 121 lines (+76/-10)
2 files modified
charmhelpers/contrib/amulet/utils.py (+15/-10)
tests/contrib/amulet/test_utils.py (+61/-0)
To merge this branch: bzr merge lp:~chris.macnaughton/charm-helpers/pids-can-be-a-list
Reviewer Review Type Date Requested Status
Ryan Beisner (community) Approve
charmers Pending
Review via email: mp+288014@code.launchpad.net

Description of the change

Allow the validate_unit_process_ids function to accept a list of valid values

To post a comment you must log in.
Revision history for this message
Ryan Beisner (1chb1n) wrote :

1. See inline comments. That existing validation block is already particularly non-beautiful ;-) and the commentary helps clarify. Let's keep that consistent in that block.

2. The variable name e_pids_length (expected process IDs length) makes sense for the existing validation blocks, but it is confusing/mis-named in the context of it being a list type. Ideas to address that?

3. I'd like to see this validated before merge by syncing this c-h LP branch into ceph-mon, then updating basic_deployment.py like so:

<icey> a ceph-mon test
<icey> looking...
<icey> beisner: https://review.openstack.org/#/c/287446/7/tests/basic_deployment.py
<icey> line 185, changed from {'ceph-osd': 2} to {'ceph-osd': True}
<icey> would rather be: {'ceph-osd': [2, 3]}

4. And finally by running the test, capturing and commenting here with a pastebin of the test
output.

review: Needs Fixing
Revision history for this message
Ryan Beisner (1chb1n) wrote :

4. (amulet) test that is.

Revision history for this message
Ryan Beisner (1chb1n) wrote :

5. Please also add a simple 1-liner docstring to each new unit test case so that when nosetests are run verbosely, we see that output.

review: Needs Fixing
Revision history for this message
Ryan Beisner (1chb1n) wrote :

Ha! Never mind 5. You've already done that. I just can't read apparently.

537. By Chris MacNaughton

review updates

Revision history for this message
Chris MacNaughton (chris.macnaughton) wrote :

Do you still want to see the changes against ceph-osd Ryan, or are the test cases enough to make you comfortable?

Revision history for this message
Ryan Beisner (1chb1n) wrote :

Thanks for the unit test coverage on this. That shows that the behavior is as intended. If we are to omit a sync/amulet test, we should also add negative unit tests here, where you pass bad scenarios and assert that the validation method has returned something other than None.

Can you add 1-per? That would make this rock solid.

review: Needs Information
538. By Chris MacNaughton

add negative proofs

Revision history for this message
Ryan Beisner (1chb1n) wrote :

I'm seeing test_accepts_bool_wrong & test_accepts_string_wrong fail in this rev (fresh venv, via `make test`).

review: Needs Fixing
Revision history for this message
Ryan Beisner (1chb1n) wrote :

Please update the *_wrong docstrings to reflect the negative aspect.

Also, I believe the *_wrong assertions should be IsNotNone.

review: Needs Fixing
539. By Chris MacNaughton

fix test

Revision history for this message
Ryan Beisner (1chb1n) wrote :

Thanks for your work on this. Looks good!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmhelpers/contrib/amulet/utils.py'
--- charmhelpers/contrib/amulet/utils.py 2016-03-18 19:08:25 +0000
+++ charmhelpers/contrib/amulet/utils.py 2016-04-05 21:46:27 +0000
@@ -601,7 +601,7 @@
601 return ('Process name count mismatch. expected, actual: {}, '601 return ('Process name count mismatch. expected, actual: {}, '
602 '{}'.format(len(expected), len(actual)))602 '{}'.format(len(expected), len(actual)))
603603
604 for (e_proc_name, e_pids_length), (a_proc_name, a_pids) in \604 for (e_proc_name, e_pids), (a_proc_name, a_pids) in \
605 zip(e_proc_names.items(), a_proc_names.items()):605 zip(e_proc_names.items(), a_proc_names.items()):
606 if e_proc_name != a_proc_name:606 if e_proc_name != a_proc_name:
607 return ('Process name mismatch. expected, actual: {}, '607 return ('Process name mismatch. expected, actual: {}, '
@@ -610,25 +610,30 @@
610 a_pids_length = len(a_pids)610 a_pids_length = len(a_pids)
611 fail_msg = ('PID count mismatch. {} ({}) expected, actual: '611 fail_msg = ('PID count mismatch. {} ({}) expected, actual: '
612 '{}, {} ({})'.format(e_sentry_name, e_proc_name,612 '{}, {} ({})'.format(e_sentry_name, e_proc_name,
613 e_pids_length, a_pids_length,613 e_pids, a_pids_length,
614 a_pids))614 a_pids))
615615
616 # If expected is not bool, ensure PID quantities match616 # If expected is a list, ensure at least one PID quantity match
617 if not isinstance(e_pids_length, bool) and \617 if isinstance(e_pids, list) and \
618 a_pids_length != e_pids_length:618 a_pids_length not in e_pids:
619 return fail_msg
620 # If expected is not bool and not list, ensure PID quantities match
621 elif not isinstance(e_pids, bool) and \
622 not isinstance(e_pids, list) and \
623 a_pids_length != e_pids:
619 return fail_msg624 return fail_msg
620 # If expected is bool True, ensure 1 or more PIDs exist625 # If expected is bool True, ensure 1 or more PIDs exist
621 elif isinstance(e_pids_length, bool) and \626 elif isinstance(e_pids, bool) and \
622 e_pids_length is True and a_pids_length < 1:627 e_pids is True and a_pids_length < 1:
623 return fail_msg628 return fail_msg
624 # If expected is bool False, ensure 0 PIDs exist629 # If expected is bool False, ensure 0 PIDs exist
625 elif isinstance(e_pids_length, bool) and \630 elif isinstance(e_pids, bool) and \
626 e_pids_length is False and a_pids_length != 0:631 e_pids is False and a_pids_length != 0:
627 return fail_msg632 return fail_msg
628 else:633 else:
629 self.log.debug('PID check OK: {} {} {}: '634 self.log.debug('PID check OK: {} {} {}: '
630 '{}'.format(e_sentry_name, e_proc_name,635 '{}'.format(e_sentry_name, e_proc_name,
631 e_pids_length, a_pids))636 e_pids, a_pids))
632 return None637 return None
633638
634 def validate_list_of_identical_dicts(self, list_of_dicts):639 def validate_list_of_identical_dicts(self, list_of_dicts):
635640
=== modified file 'tests/contrib/amulet/test_utils.py'
--- tests/contrib/amulet/test_utils.py 2015-09-09 12:03:14 +0000
+++ tests/contrib/amulet/test_utils.py 2016-04-05 21:46:27 +0000
@@ -334,3 +334,64 @@
334 "status-get: command not found", 127)334 "status-get: command not found", 127)
335 self.assertEqual(self.utils.status_get(self.sentry_unit),335 self.assertEqual(self.utils.status_get(self.sentry_unit),
336 (u"unknown", u""))336 (u"unknown", u""))
337
338
339class ValidateServicesByProcessIDTestCase(unittest.TestCase):
340
341 def setUp(self):
342 self.utils = AmuletUtils()
343 self.sentry_unit = FakeSentry()
344
345 def test_accepts_list_wrong(self):
346 """
347 Validates that it can accept a list
348 """
349 expected = {self.sentry_unit: {"foo": [3, 4]}}
350 actual = {self.sentry_unit: {"foo": [12345, 67890]}}
351 result = self.utils.validate_unit_process_ids(expected, actual)
352 self.assertIsNotNone(result)
353
354 def test_accepts_list(self):
355 """
356 Validates that it can accept a list
357 """
358 expected = {self.sentry_unit: {"foo": [2, 3]}}
359 actual = {self.sentry_unit: {"foo": [12345, 67890]}}
360 result = self.utils.validate_unit_process_ids(expected, actual)
361 self.assertIsNone(result)
362
363 def test_accepts_string(self):
364 """
365 Validates that it can accept a string
366 """
367 expected = {self.sentry_unit: {"foo": 2}}
368 actual = {self.sentry_unit: {"foo": [12345, 67890]}}
369 result = self.utils.validate_unit_process_ids(expected, actual)
370 self.assertIsNone(result)
371
372 def test_accepts_string_wrong(self):
373 """
374 Validates that it can accept a string
375 """
376 expected = {self.sentry_unit: {"foo": 3}}
377 actual = {self.sentry_unit: {"foo": [12345, 67890]}}
378 result = self.utils.validate_unit_process_ids(expected, actual)
379 self.assertIsNotNone(result)
380
381 def test_accepts_bool(self):
382 """
383 Validates that it can accept a boolean
384 """
385 expected = {self.sentry_unit: {"foo": True}}
386 actual = {self.sentry_unit: {"foo": [12345, 67890]}}
387 result = self.utils.validate_unit_process_ids(expected, actual)
388 self.assertIsNone(result)
389
390 def test_accepts_bool_wrong(self):
391 """
392 Validates that it can accept a boolean
393 """
394 expected = {self.sentry_unit: {"foo": True}}
395 actual = {self.sentry_unit: {"foo": []}}
396 result = self.utils.validate_unit_process_ids(expected, actual)
397 self.assertIsNotNone(result)

Subscribers

People subscribed via source and target branches