summaryrefslogtreecommitdiff
path: root/unit_tests
diff options
authorBilly Olsen <billy.olsen@canonical.com>2014-12-16 23:39:57 -0700
committerBilly Olsen <billy.olsen@canonical.com>2014-12-16 23:39:57 -0700
commit37c13bbb3939e0c66e8c4c624fd2b20ce0e36ee8 (patch)
treedada81308f17ffa4cebc539d9ceb16cc88d402f5 /unit_tests
parent0396bd9803c0aa376cfb4dc0cf012d66755d79f3 (diff)
Add more unit test coverage.
Diffstat (limited to 'unit_tests')
-rw-r--r--unit_tests/test_hooks.py165
1 files changed, 151 insertions, 14 deletions
diff --git a/unit_tests/test_hooks.py b/unit_tests/test_hooks.py
index 8836087..4e40bdf 100644
--- a/unit_tests/test_hooks.py
+++ b/unit_tests/test_hooks.py
@@ -3,6 +3,7 @@ from mock import patch
import hooks
from test_utils import CharmTestCase
+from pymongo.errors import OperationFailure
# Defines a set of functions to patch on the hooks object. Any of these
# methods will be patched by default on the default invocations of the
@@ -29,31 +30,20 @@ class MongoHooksTest(CharmTestCase):
# test_config dictionary
self.config.side_effect = self.test_config.get
- # Note: if we need to mock a specific class of an object, we need to
- # invoke the patch.object rather than simply mocking the module itself.
- # This is typically recommended for patching any object which belongs
- # to the object under test (lookup partial-mocks for more information).
@patch.object(hooks, 'restart_mongod')
@patch.object(hooks, 'enable_replset')
# Note: patching the os.environ dictionary in-line here so there's no
# additional parameter sent into the function
@patch.dict('os.environ', JUJU_UNIT_NAME='fake-unit/0')
- def test_replica_set_relation_joined(self, mock_enable, mock_restart):
- # only have 1 invocation of the unit_get, so we'll just tell it what
- # to return. Can change to be more sophisticated when necessary.
+ def test_replica_set_relation_joined(self, mock_enable_replset,
+ mock_restart):
self.unit_get.return_value = 'private.address'
self.test_config.set('port', '1234')
self.test_config.set('replicaset', 'fake-replicaset')
self.relation_id.return_value = 'fake-relation-id'
- # Partial mock to control the flow around the if check for the enable
- # restart.
- mock_enable.return_value = False
+ mock_enable_replset.return_value = False
- # This tests the trigger of firing the relation-joined as the python
- # invocation works. However, it doesn't seem to accept all the mocking
- # in this case, so I'll just invoke the function directly.
- # hooks.hooks.execute(['hooks/replicaset-relation-joined'])
hooks.replica_set_relation_joined()
# Verify that mongodb was NOT restarted since the replicaset we claimed
@@ -67,3 +57,150 @@ class MongoHooksTest(CharmTestCase):
'type': 'replset'}
# Check that the relation data was set as we expect it to be set.
self.relation_set.assert_called_with('fake-relation-id', exp_rel_vals)
+
+ mock_enable_replset.reset_mock()
+ self.relation_set.reset_mock()
+ mock_enable_replset.return_value = True
+
+ hooks.replica_set_relation_joined()
+
+ self.assertTrue(mock_restart.called)
+ self.relation_set.assert_called_with('fake-relation-id', exp_rel_vals)
+
+ def test_init_replset_no_master_node(self):
+ retval = hooks.init_replset(master_node=None)
+ self.assertFalse(retval)
+
+ @patch.object(hooks, 'admin_command')
+ @patch.object(hooks, 'MongoClient')
+ @patch.object(hooks, 'config')
+ @patch.object(hooks, 'mongo_client')
+ @patch('time.sleep')
+ def test_init_repl_set(self, mock_sleep, mock_mongo_client_fn,
+ mock_config, mock_mongo_client, mock_admin_command):
+ master_node = 'mongo.unit.private.address'
+ mock_mongo_client_fn.return_value = False
+
+ mock_config.return_value = {'replicaset': 'foo',
+ 'private-address': 'mongo.local',
+ 'port': '12345'}
+
+ # Put the OK state (1) at the end and check the loop.
+ ret_values = [{'myState': x} for x in [0, 2, 3, 4, 1]]
+ mock_admin_command.side_effect = ret_values
+
+ hooks.init_replset(master_node)
+
+ mock_admin_command.assert_called()
+ self.assertEqual(len(ret_values), mock_admin_command.call_count)
+ self.assertEqual(len(ret_values) + 1, mock_sleep.call_count)
+
+ mock_admin_command.reset_mock()
+ exc = [OperationFailure('Received replSetInitiate'),
+ OperationFailure('unhandled')]
+ mock_admin_command.side_effect = exc
+
+ try:
+ hooks.init_replset(master_node)
+ self.assertTrue(False, msg="Expected error")
+ except OperationFailure:
+ pass
+
+ mock_admin_command.assert_called()
+ self.assertEqual(2, mock_admin_command.call_count)
+
+ @patch.object(hooks, 'mongo_client_smart')
+ def test_join_replset(self, mock_mongo_client):
+ hooks.join_replset()
+ self.assertFalse(mock_mongo_client.called)
+
+ mock_mongo_client.reset_mock()
+ hooks.join_replset(master_node='mongo.local')
+ self.assertFalse(mock_mongo_client.called)
+
+ mock_mongo_client.reset_mock()
+ hooks.join_replset(host='fake-host')
+ self.assertFalse(mock_mongo_client.called)
+
+ mock_mongo_client.reset_mock()
+ hooks.join_replset(master_node='mongo.local', host='fake-host')
+ mock_mongo_client.assert_called_with('localhost',
+ 'rs.add("fake-host")')
+
+ @patch.object(hooks, 'mongo_client')
+ def test_leave_replset(self, mock_mongo_client):
+ hooks.leave_replset()
+ self.assertFalse(mock_mongo_client.called)
+
+ mock_mongo_client.reset_mock()
+ hooks.leave_replset(master_node='mongo.local')
+ self.assertFalse(mock_mongo_client.called)
+
+ mock_mongo_client.reset_mock()
+ hooks.leave_replset(host='fake-host')
+ self.assertFalse(mock_mongo_client.called)
+
+ mock_mongo_client.reset_mock()
+ hooks.leave_replset('mongo.local', 'fake-host')
+ mock_mongo_client.assert_called_with('mongo.local',
+ 'rs.remove("fake-host")')
+
+ @patch.object(hooks, 'apt_install')
+ @patch.object(hooks, 'apt_update')
+ @patch.object(hooks, 'add_source')
+ def test_install_hook(self, mock_add_source, mock_apt_update,
+ mock_apt_install):
+ self.test_config.set('source', 'fake-source')
+ self.test_config.set('key', 'fake-key')
+
+ hooks.install_hook()
+ mock_add_source.assert_called_with('fake-source', 'fake-key')
+ mock_apt_update.assert_called_with(fatal=True)
+ mock_apt_install.assert_called_with(packages=hooks.INSTALL_PACKAGES,
+ fatal=True)
+
+ @patch.object(hooks, 'admin_command')
+ @patch.object(hooks, 'MongoClient')
+ @patch('time.sleep')
+ def test_am_i_primary(self, mock_sleep, mock_mongo_client, mock_admin_cmd):
+ mock_admin_cmd.side_effect = [{'myState': x} for x in xrange(5)]
+ expected_results = [True if x == 1 else False for x in xrange(5)]
+
+ # Check expected return values each time...
+ for exp in expected_results:
+ rv = hooks.am_i_primary()
+ self.assertEqual(exp, rv)
+
+ @patch.object(hooks, 'admin_command')
+ @patch.object(hooks, 'MongoClient')
+ @patch('time.sleep')
+ def test_am_i_primary_too_many_attempts(self, mock_sleep, mock_mongo_client,
+ mock_admin_cmd):
+ msg = 'replSetInitiate - should come online shortly'
+ mock_admin_cmd.side_effect = [OperationFailure(msg) for x in xrange(10)]
+
+ try:
+ rv = hooks.am_i_primary()
+ self.assertTrue(False, 'Expected failure.')
+ except hooks.TimeoutException:
+ self.assertEqual(mock_admin_cmd.call_count, 9)
+ pass
+
+ @patch.object(hooks, 'admin_command')
+ @patch.object(hooks, 'MongoClient')
+ @patch('time.sleep')
+ def test_am_i_primary_operation_failures(self, mock_sleep,
+ mock_mongo_client, mock_admin_cmd):
+ mock_admin_cmd.side_effect = OperationFailure('EMPTYCONFIG')
+
+ rv = hooks.am_i_primary()
+ mock_admin_cmd.assert_called()
+ self.assertFalse(rv)
+
+ mock_admin_cmd.reset_mock()
+ mock_admin_cmd.side_effect = OperationFailure('unexpected failure')
+ try:
+ hooks.am_i_primary()
+ except OperationFailure:
+ mock_admin_cmd.assert_called()
+