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
1=== modified file 'charmhelpers/contrib/amulet/utils.py'
2--- charmhelpers/contrib/amulet/utils.py 2016-03-18 19:08:25 +0000
3+++ charmhelpers/contrib/amulet/utils.py 2016-04-05 21:46:27 +0000
4@@ -601,7 +601,7 @@
5 return ('Process name count mismatch. expected, actual: {}, '
6 '{}'.format(len(expected), len(actual)))
7
8- for (e_proc_name, e_pids_length), (a_proc_name, a_pids) in \
9+ for (e_proc_name, e_pids), (a_proc_name, a_pids) in \
10 zip(e_proc_names.items(), a_proc_names.items()):
11 if e_proc_name != a_proc_name:
12 return ('Process name mismatch. expected, actual: {}, '
13@@ -610,25 +610,30 @@
14 a_pids_length = len(a_pids)
15 fail_msg = ('PID count mismatch. {} ({}) expected, actual: '
16 '{}, {} ({})'.format(e_sentry_name, e_proc_name,
17- e_pids_length, a_pids_length,
18+ e_pids, a_pids_length,
19 a_pids))
20
21- # If expected is not bool, ensure PID quantities match
22- if not isinstance(e_pids_length, bool) and \
23- a_pids_length != e_pids_length:
24+ # If expected is a list, ensure at least one PID quantity match
25+ if isinstance(e_pids, list) and \
26+ a_pids_length not in e_pids:
27+ return fail_msg
28+ # If expected is not bool and not list, ensure PID quantities match
29+ elif not isinstance(e_pids, bool) and \
30+ not isinstance(e_pids, list) and \
31+ a_pids_length != e_pids:
32 return fail_msg
33 # If expected is bool True, ensure 1 or more PIDs exist
34- elif isinstance(e_pids_length, bool) and \
35- e_pids_length is True and a_pids_length < 1:
36+ elif isinstance(e_pids, bool) and \
37+ e_pids is True and a_pids_length < 1:
38 return fail_msg
39 # If expected is bool False, ensure 0 PIDs exist
40- elif isinstance(e_pids_length, bool) and \
41- e_pids_length is False and a_pids_length != 0:
42+ elif isinstance(e_pids, bool) and \
43+ e_pids is False and a_pids_length != 0:
44 return fail_msg
45 else:
46 self.log.debug('PID check OK: {} {} {}: '
47 '{}'.format(e_sentry_name, e_proc_name,
48- e_pids_length, a_pids))
49+ e_pids, a_pids))
50 return None
51
52 def validate_list_of_identical_dicts(self, list_of_dicts):
53
54=== modified file 'tests/contrib/amulet/test_utils.py'
55--- tests/contrib/amulet/test_utils.py 2015-09-09 12:03:14 +0000
56+++ tests/contrib/amulet/test_utils.py 2016-04-05 21:46:27 +0000
57@@ -334,3 +334,64 @@
58 "status-get: command not found", 127)
59 self.assertEqual(self.utils.status_get(self.sentry_unit),
60 (u"unknown", u""))
61+
62+
63+class ValidateServicesByProcessIDTestCase(unittest.TestCase):
64+
65+ def setUp(self):
66+ self.utils = AmuletUtils()
67+ self.sentry_unit = FakeSentry()
68+
69+ def test_accepts_list_wrong(self):
70+ """
71+ Validates that it can accept a list
72+ """
73+ expected = {self.sentry_unit: {"foo": [3, 4]}}
74+ actual = {self.sentry_unit: {"foo": [12345, 67890]}}
75+ result = self.utils.validate_unit_process_ids(expected, actual)
76+ self.assertIsNotNone(result)
77+
78+ def test_accepts_list(self):
79+ """
80+ Validates that it can accept a list
81+ """
82+ expected = {self.sentry_unit: {"foo": [2, 3]}}
83+ actual = {self.sentry_unit: {"foo": [12345, 67890]}}
84+ result = self.utils.validate_unit_process_ids(expected, actual)
85+ self.assertIsNone(result)
86+
87+ def test_accepts_string(self):
88+ """
89+ Validates that it can accept a string
90+ """
91+ expected = {self.sentry_unit: {"foo": 2}}
92+ actual = {self.sentry_unit: {"foo": [12345, 67890]}}
93+ result = self.utils.validate_unit_process_ids(expected, actual)
94+ self.assertIsNone(result)
95+
96+ def test_accepts_string_wrong(self):
97+ """
98+ Validates that it can accept a string
99+ """
100+ expected = {self.sentry_unit: {"foo": 3}}
101+ actual = {self.sentry_unit: {"foo": [12345, 67890]}}
102+ result = self.utils.validate_unit_process_ids(expected, actual)
103+ self.assertIsNotNone(result)
104+
105+ def test_accepts_bool(self):
106+ """
107+ Validates that it can accept a boolean
108+ """
109+ expected = {self.sentry_unit: {"foo": True}}
110+ actual = {self.sentry_unit: {"foo": [12345, 67890]}}
111+ result = self.utils.validate_unit_process_ids(expected, actual)
112+ self.assertIsNone(result)
113+
114+ def test_accepts_bool_wrong(self):
115+ """
116+ Validates that it can accept a boolean
117+ """
118+ expected = {self.sentry_unit: {"foo": True}}
119+ actual = {self.sentry_unit: {"foo": []}}
120+ result = self.utils.validate_unit_process_ids(expected, actual)
121+ self.assertIsNotNone(result)

Subscribers

People subscribed via source and target branches