Merge lp:~billy-olsen/charms/trusty/mongodb/unit-tests-part-deux into lp:~mariosplivalo/charms/trusty/mongodb/replsets-fix-try

Proposed by Billy Olsen
Status: Merged
Approved by: Mario Splivalo
Approved revision: 87
Merge reported by: Mario Splivalo
Merged at revision: not available
Proposed branch: lp:~billy-olsen/charms/trusty/mongodb/unit-tests-part-deux
Merge into: lp:~mariosplivalo/charms/trusty/mongodb/replsets-fix-try
Diff against target: 313 lines (+188/-22)
3 files modified
hooks/hooks.py (+19/-17)
unit_tests/test_hooks.py (+165/-1)
unit_tests/test_utils.py (+4/-4)
To merge this branch: bzr merge lp:~billy-olsen/charms/trusty/mongodb/unit-tests-part-deux
Reviewer Review Type Date Requested Status
Mario Splivalo Approve
Review via email: mp+245070@code.launchpad.net

Description of the change

Finish uint test coverage for new functions

To post a comment you must log in.
Revision history for this message
Mario Splivalo (mariosplivalo) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/hooks.py'
2--- hooks/hooks.py 2014-12-17 07:31:14 +0000
3+++ hooks/hooks.py 2014-12-18 06:53:34 +0000
4@@ -49,15 +49,16 @@
5 pass
6
7 from charmhelpers.core.hookenv import (
8+ close_port,
9 config,
10+ local_unit,
11+ open_port,
12 unit_get,
13 relation_get,
14 relation_set,
15 relations_of_type,
16 relation_id,
17 relation_ids,
18- open_port,
19- close_port,
20 Hooks,
21 DEBUG,
22 )
23@@ -190,6 +191,10 @@
24 return((None, None))
25
26
27+class MasterNotFoundException(Exception):
28+ pass
29+
30+
31 class TimeoutException(Exception):
32 pass
33
34@@ -384,13 +389,8 @@
35 if command is None:
36 return(False)
37
38- cmd_line = []
39- cmd_line.append('mongo')
40- cmd_line.append('--quiet')
41- cmd_line.append('--host')
42- cmd_line.append(host)
43- cmd_line.append('--eval')
44- cmd_line.append('printjson(%s)' % command)
45+ cmd_line = ['mongo', '--quiet', '--host', host,
46+ '--eval', 'printjson(%s)' % command]
47 juju_log("mongo_client_smart executing: %s" % str(cmd_line), DEBUG)
48
49 for i in xrange(0, 10):
50@@ -1078,7 +1078,7 @@
51
52
53 def get_unit_id():
54- return os.environ.get('JUJU_UNIT_NAME').split('/')[1]
55+ return local_unit().split('/')[1]
56
57
58 def get_replicaset_members():
59@@ -1110,6 +1110,7 @@
60 (idx, hostname, port) = member
61 if "%s:%s" % (hostname, port) == replica:
62 return member
63+ raise MasterNotFoundException("%s was not found." % (replica))
64
65 return (current_id,
66 unit_get('private-address'),
67@@ -1145,11 +1146,14 @@
68 def replica_set_relation_changed():
69 (idx, master_hostname, master_port) = get_replicaset_master()
70
71+ private_address = unit_get('private-address')
72+ remote_hostname = relation_get('hostname')
73+
74 juju_log('replica_set_relation_changed-start')
75- juju_log('I am: %s' % unit_get('private-address'))
76- juju_log('Joiner: %s' % relation_get('hostname'))
77+ juju_log('I am: %s' % (private_address))
78+ juju_log('Joiner: %s' % (remote_hostname))
79
80- if relation_get('hostname') is None:
81+ if remote_hostname is None:
82 juju_log('Joiner not ready yet... bailing out')
83 return
84
85@@ -1168,10 +1172,8 @@
86 (master_hostname, master_port), DEBUG)
87 init_replset("%s:%s" % (master_hostname, master_port))
88
89- unit = "%s:%s" % (unit_get('private-address'),
90- config('port'))
91- unit_remote = "%s:%s" % (relation_get('hostname'),
92- relation_get('port'))
93+ unit = "%s:%s" % (private_address, config('port'))
94+ unit_remote = "%s:%s" % (remote_hostname, relation_get('port'))
95 juju_log("DEBUG: %s - %s" % (unit, master_hostname))
96
97 # If this is primary, add joined unit to replicaset
98
99=== modified file 'unit_tests/test_hooks.py'
100--- unit_tests/test_hooks.py 2014-12-17 07:31:14 +0000
101+++ unit_tests/test_hooks.py 2014-12-18 06:53:34 +0000
102@@ -1,4 +1,4 @@
103-from mock import patch
104+from mock import patch, call
105
106 import hooks
107
108@@ -30,6 +30,7 @@
109 # the hooks object will return the value that is set in the test case's
110 # test_config dictionary
111 self.config.side_effect = self.test_config.get
112+ self.relation_get.side_effect = self.test_relation.get
113
114 @patch.object(hooks, 'restart_mongod')
115 @patch.object(hooks, 'enable_replset')
116@@ -204,6 +205,7 @@
117 mock_admin_cmd.side_effect = OperationFailure('unexpected failure')
118 try:
119 hooks.am_i_primary()
120+ self.assertFalse(True, "Expected OperationFailure to be raised")
121 except OperationFailure:
122 mock_admin_cmd.assert_called()
123
124@@ -265,3 +267,165 @@
125 % ('fake-host', 'fake-command'))
126 mock_subprocess.assert_called_once_with(expected_cmd, shell=True)
127 self.assertFalse(rv)
128+
129+ @patch.object(hooks, 'local_unit')
130+ def test_get_unit_id(self, mock_local_unit):
131+ mock_local_unit.return_value = 'fake-mongo-unit/2'
132+ self.assertEqual('2', hooks.get_unit_id())
133+
134+ @patch.object(hooks, 'relation_get')
135+ @patch.object(hooks, 'relations_of_type')
136+ def test_get_replicaset_members(self, mock_relations,
137+ mock_relation_get):
138+ mock_relations.return_value = [{'__unit__': 'mongodb/0'},
139+ {'__unit__': 'mongodb/1'}]
140+
141+ config_stuff = {'mongodb/0': {'install-order': 1,
142+ 'hostname': 'juju-local-unit-1',
143+ 'port': '27817'},
144+ 'mongodb/1': {'install-order': 0,
145+ 'hostname': 'juju-local-unit-2',
146+ 'port': '27817'}}
147+
148+ def side_effect(key, member):
149+ member_info = config_stuff.get(member, None)
150+ if member_info is None:
151+ return None
152+
153+ return member_info.get(key, None)
154+
155+ mock_relation_get.side_effect = side_effect
156+ members = hooks.get_replicaset_members()
157+ self.assertEqual(2, len(members))
158+
159+ # Expect a re-ordering based on the install-order
160+ exp_members = [(0, 'juju-local-unit-2', '27817'),
161+ (1, 'juju-local-unit-1', '27817')]
162+ self.assertEqual(members, exp_members)
163+
164+ @patch.object(hooks, 'get_replicaset_members')
165+ @patch.object(hooks, 'get_unit_id')
166+ @patch.object(hooks, 'unit_get')
167+ def test_get_replicaset_master(self, mock_unit_get, mock_unit_id,
168+ mock_members):
169+ mock_unit_id.return_value = 0
170+ mock_unit_get.return_value = 'juju-local-unit-1'
171+
172+ self.test_config.set('port', '12345')
173+
174+ # First check no members
175+ mock_members.return_value = []
176+ master = hooks.get_replicaset_master()
177+ self.assertEqual(master, (0, 'juju-local-unit-1', '12345'))
178+
179+ # Check auto, curr unit is lowest unit
180+ self.test_config.set('replicaset_master', 'auto')
181+ mock_members.return_value = [(1, 'juju-local-unit-2', '12345'),
182+ (2, 'juju-local-unit-3', '12345')]
183+ master = hooks.get_replicaset_master()
184+ self.assertEqual(master, (0, 'juju-local-unit-1', '12345'))
185+
186+ # Check auto, curr unit is NOT lowest unit
187+ mock_unit_id.return_value = 3
188+ master = hooks.get_replicaset_master()
189+ self.assertEqual(master, (1, 'juju-local-unit-2', '12345'))
190+
191+ # Check not-auto, master found
192+ self.test_config.set('replicaset_master', 'juju-local-unit-3:12345')
193+ master = hooks.get_replicaset_master()
194+ self.assertEqual(master, (2, 'juju-local-unit-3', '12345'))
195+
196+ # Check not-auto, master NOT found
197+ self.test_config.set('replicaset_master', 'nonexistent-unit:7890')
198+ try:
199+ master = hooks.get_replicaset_master()
200+ self.assertTrue(False, 'replicaset master specified should error')
201+ except hooks.MasterNotFoundException:
202+ pass
203+
204+ @patch.object(hooks, 'am_i_primary')
205+ @patch.object(hooks, 'init_replset')
206+ @patch.object(hooks, 'relation_get')
207+ @patch.object(hooks, 'peer_units')
208+ @patch.object(hooks, 'oldest_peer')
209+ @patch.object(hooks, 'join_replset')
210+ @patch.object(hooks, 'unit_get')
211+ @patch.object(hooks, 'get_replicaset_master')
212+ def test_replica_set_relation_changed(self, mock_master, mock_unit_get,
213+ mock_join_replset, mock_oldest_peer,
214+ mock_peer_units, mock_relation_get,
215+ mock_init_replset, mock_is_primary):
216+ # set the unit_get('private-address')
217+ mock_unit_get.return_value = 'juju-local-unit-0.local'
218+ mock_master.return_value = (0, 'juju-local-unit-0', '12345')
219+ mock_relation_get.return_value = None
220+
221+ # Test when remote hostname is None, should not join
222+ hooks.replica_set_relation_changed()
223+ self.assertEqual(0, mock_join_replset.call_count)
224+
225+ # Test remote hostname is valid, but master is somehow not defined
226+ mock_join_replset.reset_mock()
227+ mock_master.reset_mock()
228+ mock_master.return_value = (0, None, None)
229+ mock_relation_get.return_value = 'juju-local-unit-0'
230+
231+ hooks.replica_set_relation_changed()
232+
233+ self.assertEqual(0, mock_join_replset.call_count)
234+
235+ # Test when not oldest peer, don't init replica set
236+ mock_peer_units.return_value = ['mongodb/1', 'mongodb/2']
237+ mock_oldest_peer.return_value = False
238+
239+ hooks.replica_set_relation_changed()
240+
241+ self.assertEqual(mock_init_replset.call_count, 0)
242+
243+ # Test when this is the oldest peer
244+ mock_master.reset_mock()
245+ mock_master.return_value = (0, 'juju-unit-0', '12345')
246+ mock_oldest_peer.reset_mock()
247+ mock_oldest_peer.return_value = True
248+ mock_is_primary.return_value = False
249+
250+ hooks.replica_set_relation_changed()
251+ call1 = call('juju-unit-0:12345')
252+
253+ mock_init_replset.assert_has_calls(call1)
254+
255+ # Test when its also the PRIMARY
256+ mock_relation_get.reset_mock()
257+ mock_relation_get.side_effect = ['juju-remote-unit-0', '12345']
258+ mock_oldest_peer.reset_mock()
259+ mock_oldest_peer.return_value = False
260+ mock_is_primary.reset_mock()
261+ mock_is_primary.return_value = True
262+
263+ hooks.replica_set_relation_changed()
264+ call1 = call('juju-local-unit-0.local:27017',
265+ 'juju-remote-unit-0:12345')
266+ mock_join_replset.assert_has_calls(call1)
267+
268+ @patch.object(hooks, 'unit_get')
269+ @patch.object(hooks, 'leave_replset')
270+ @patch.object(hooks, 'am_i_primary')
271+ def test_replica_set_relation_departed(self, mock_am_i_primary,
272+ mock_leave_replset, mock_unit_get):
273+ mock_am_i_primary.return_value = False
274+ hooks.replica_set_relation_departed()
275+
276+ self.assertEqual(0, mock_leave_replset.call_count)
277+
278+ mock_am_i_primary.reset_mock()
279+ mock_am_i_primary.return_value = True
280+ mock_unit_get.return_value = 'juju-local'
281+
282+ self.test_relation.set({'hostname': 'juju-remote',
283+ 'port': '27017'})
284+ mock_leave_replset.reset_mock()
285+
286+ hooks.replica_set_relation_departed()
287+
288+ call1 = call('juju-local:27017', 'juju-remote:27017')
289+ mock_leave_replset.assert_has_calls(call1)
290
291=== modified file 'unit_tests/test_utils.py'
292--- unit_tests/test_utils.py 2014-12-13 00:18:15 +0000
293+++ unit_tests/test_utils.py 2014-12-18 06:53:34 +0000
294@@ -91,9 +91,9 @@
295 return self.config
296
297 def set(self, attr, value):
298- if attr not in self.config:
299- raise KeyError
300- self.config[attr] = value
301+ if attr not in self.config:
302+ raise KeyError
303+ self.config[attr] = value
304
305
306 class TestRelation(object):
307@@ -107,5 +107,5 @@
308 if attr is None:
309 return self.relation_data
310 elif attr in self.relation_data:
311- return self.relation_data[attr]
312+ return self.relation_data.get(attr)
313 return None

Subscribers

People subscribed via source and target branches

to all changes: