freezer-api/tests/test_db_init.py
Fabrizio Vanni 4faa13b8e7 Add support for elasticsearch number of replicas
It is now possible to specify the number of replicas of the freezer
index in the elasticsearch database.

The value is set by the freezer-db-init script and can be specified
either as a command line parameter or defined in the freezer-api config
file.

When not specified it is set to the default value 2.

Adds the following command line parameter to the freeze-db-init script:

    -r  --replicas <N>

Adds the following parameter to the [storage] group of the
freezer-api.conf file:

    number_of_replicas = N

Change-Id: I210dce8bf634727f52c87152c3d036cc4d7065b5
2015-10-28 09:49:35 +00:00

320 lines
15 KiB
Python

"""
Copyright 2015 Hewlett-Packard
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This product includes cryptographic software written by Eric Young
(eay@cryptsoft.com). This product includes software written by Tim
Hudson (tjh@cryptsoft.com).
========================================================================
"""
import os
import unittest
from mock import Mock, patch
import requests
from freezer_api.cmd.db_init import (ElastichsearchEngine,
get_args,
find_config_file,
parse_config_file,
get_db_params,
main,
DEFAULT_CONF_PATH,
MergeMappingException)
from freezer_api.common import db_mappings
class TestElasticsearchEngine(unittest.TestCase):
def setUp(self):
self.test_mappings = {
'jobs': {"properties": {"job_id": {"type": "string"}}},
'backups': {"properties": {"backup_id": {"type": "string"}}},
'clients': {"properties": {"client_id": {"type": "string"}}},
}
self.mock_resp = Mock()
self.mock_args = Mock()
self.mock_args.test_only = False
self.mock_args.always_yes = False
self.mock_args.verbose = 1
self.mock_args.select_mapping = ''
self.mock_args.erase = False
self.mock_args.replicas = 0
self.es_manager = ElastichsearchEngine(es_url='http://test:9333',
es_index='freezerindex',
args=self.mock_args)
def test_new(self):
self.assertIsInstance(self.es_manager, ElastichsearchEngine)
@patch.object(ElastichsearchEngine, 'check_index_exists')
@patch.object(ElastichsearchEngine, 'mapping_match')
@patch.object(ElastichsearchEngine, 'askput_mapping')
@patch.object(ElastichsearchEngine, 'set_number_of_replicas')
def test_put_mappings_does_nothing_when_mappings_match(self,
mock_set_number_of_replicas,
mock_askput_mapping,
mock_mapping_match,
mock_check_index_exists):
self.es_manager.put_mappings(self.test_mappings)
self.assertEquals(mock_askput_mapping.call_count, 0)
@patch.object(ElastichsearchEngine, 'check_index_exists')
@patch.object(ElastichsearchEngine, 'mapping_match')
@patch.object(ElastichsearchEngine, 'askput_mapping')
@patch.object(ElastichsearchEngine, 'set_number_of_replicas')
def test_put_mappings_calls_askput_when_mappings_match_not(self,
mock_set_number_of_replicas,
mock_askput_mapping,
mock_mapping_match,
mock_check_index_exists):
mock_mapping_match.return_value = False
self.es_manager.put_mappings(self.test_mappings)
self.assertEquals(mock_askput_mapping.call_count, 3)
@patch.object(ElastichsearchEngine, 'proceed')
@patch.object(ElastichsearchEngine, 'delete_type')
@patch.object(ElastichsearchEngine, 'put_mapping')
@patch.object(ElastichsearchEngine, 'set_number_of_replicas')
def test_askput_calls_delete_and_put_mappings_when_always_yes_and_erase(self,
mock_set_number_of_replicas,
mock_put_mapping,
mock_delete_type,
mock_proceed):
self.mock_args.yes = True
self.mock_args.erase = True
mock_put_mapping.side_effect = [MergeMappingException('regular test failure'), 0]
res = self.es_manager.askput_mapping('jobs', self.test_mappings['jobs'])
self.assertTrue(mock_put_mapping.called)
mock_delete_type.assert_called_once_with('jobs')
def test_askput_does_nothing_when_test_only(self):
self.mock_args.test_only = True
res = self.es_manager.askput_mapping('jobs', self.test_mappings['jobs'])
self.assertEquals(None, res)
@patch('freezer_api.cmd.db_init.requests')
def test_mapping_match_not_found_returns_false(self, mock_requests):
self.mock_resp.status_code = 404
mock_requests.codes.OK = 200
mock_requests.codes.NOT_FOUND = 404
mock_requests.get.return_value = self.mock_resp
res = self.es_manager.mapping_match('jobs', self.test_mappings['jobs'])
self.assertFalse(res)
@patch('freezer_api.cmd.db_init.requests')
def test_mapping_match_raises_Exception_on_response_not_in_200_404(self, mock_requests):
self.mock_resp.status_code = 500
mock_requests.get.return_value = self.mock_resp
mock_requests.codes.OK = 200
mock_requests.codes.NOT_FOUND = 404
self.assertRaises(Exception, self.es_manager.mapping_match,
'jobs', self.test_mappings['jobs'])
@patch('freezer_api.cmd.db_init.requests')
def test_mapping_match_return_true_when_mapping_matches(self, mock_requests):
self.mock_resp.status_code = 200
self.mock_resp.json.return_value = {"freezerindex": {"mappings": {"jobs": {"properties": {"job_id": {"type": "string"}}}}}}
mock_requests.get.return_value = self.mock_resp
mock_requests.codes.OK = 200
mock_requests.codes.NOT_FOUND = 404
res = self.es_manager.mapping_match('jobs', self.test_mappings['jobs'])
self.assertTrue(res)
@patch('freezer_api.cmd.db_init.requests')
def test_mapping_match_return_false_when_mapping_matches_not(self, mock_requests):
self.mock_resp.status_code = 200
self.mock_resp.text = '{"freezerindex": {"mappings": {"jobs":{"properties": {"job_id": {"type": "balloon"}}}}}}'
mock_requests.get.return_value = self.mock_resp
mock_requests.codes.OK = 200
mock_requests.codes.NOT_FOUND = 404
res = self.es_manager.mapping_match('jobs', self.test_mappings['jobs'])
self.assertFalse(res)
@patch('freezer_api.cmd.db_init.requests')
def test_delete_type_returns_none_on_success(self, mock_requests):
self.mock_resp.status_code = 200
mock_requests.codes.OK = 200
mock_requests.codes.NOT_FOUND = 404
mock_requests.delete.return_value = self.mock_resp
res = self.es_manager.delete_type('jobs')
self.assertIsNone(res)
@patch('freezer_api.cmd.db_init.requests')
def test_delete_type_raises_Exception_on_response_code_not_200(self, mock_requests):
self.mock_resp.status_code = requests.codes.BAD_REQUEST
mock_requests.delete.return_value = self.mock_resp
mock_requests.codes.OK = 200
mock_requests.codes.BAD_REQUEST = 400
mock_requests.codes.NOT_FOUND = 404
self.assertRaises(Exception, self.es_manager.delete_type, 'jobs')
@patch('freezer_api.cmd.db_init.requests')
def test_put_mapping_returns_none_on_success(self, mock_requests):
self.mock_resp.status_code = 200
mock_requests.put.return_value = self.mock_resp
mock_requests.codes.OK = 200
mock_requests.codes.NOT_FOUND = 404
res = self.es_manager.put_mapping('jobs', self.test_mappings['jobs'])
self.assertIsNone(res)
url = 'http://test:9333/freezerindex/_mapping/jobs'
data = '{"properties": {"job_id": {"type": "string"}}}'
mock_requests.put.assert_called_with(url, data=data)
@patch('freezer_api.cmd.db_init.requests')
def test_put_mapping_raises_Exception_on_response_code_not_200(self, mock_requests):
self.mock_resp.status_code = 500
mock_requests.put.return_value = self.mock_resp
mock_requests.codes.OK = 200
mock_requests.codes.NOT_FOUND = 404
self.assertRaises(Exception, self.es_manager.put_mapping, 'jobs', self.test_mappings['jobs'])
def test_proceed_returns_true_on_user_y(self):
with patch('__builtin__.raw_input', return_value='y') as _raw_input:
res = self.es_manager.proceed('fancy a drink ?')
self.assertTrue(res)
_raw_input.assert_called_once_with('fancy a drink ?')
def test_proceed_returns_false_on_user_n(self):
with patch('__builtin__.raw_input', return_value='n') as _raw_input:
res = self.es_manager.proceed('are you drunk ?')
self.assertFalse(res)
_raw_input.assert_called_once_with('are you drunk ?')
def test_proceed_returns_true_when_always_yes(self):
res = self.es_manager.proceed('ask me not', True)
self.assertTrue(res)
@patch('freezer_api.cmd.db_init.requests')
def test_check_index_exists_ok_when_index_exists(self, mock_requests):
self.mock_resp.status_code = 200
mock_requests.post.return_value = self.mock_resp
mock_requests.codes.OK = 200
mock_requests.codes.BAD_REQUEST = 400
res = self.es_manager.check_index_exists()
self.assertEquals(res, None)
@patch('freezer_api.cmd.db_init.requests')
def test_check_index_exists_ok_when_index_not_exists(self, mock_requests):
self.mock_resp.status_code = 400
mock_requests.post.return_value = self.mock_resp
mock_requests.codes.OK = 200
mock_requests.codes.BAD_REQUEST = 400
res = self.es_manager.check_index_exists()
self.assertEquals(res, None)
@patch('freezer_api.cmd.db_init.requests')
def test_check_index_raises_Exception_when_return_code_not_in_OK_BADREQ(self, mock_requests):
self.mock_resp.status_code = 500
mock_requests.post.return_value = self.mock_resp
mock_requests.codes.OK = 200
mock_requests.codes.BAD_REQUEST = 400
self.assertRaises(Exception, self.es_manager.check_index_exists)
class TestDbInit(unittest.TestCase):
def setUp(self):
self.mock_args = Mock()
self.mock_args.test_only = False
self.mock_args.always_yes = False
self.mock_args.verbose = 1
self.mock_args.select_mapping = ''
self.mock_args.erase = False
@patch('freezer_api.cmd.db_init.argparse.ArgumentParser')
def test_get_args_calls_add_argument(self, mock_ArgumentParser):
mock_arg_parser = Mock()
mock_ArgumentParser.return_value = mock_arg_parser
retval = get_args([])
call_count = mock_arg_parser.add_argument.call_count
self.assertGreater(call_count, 6)
@patch('freezer_api.cmd.db_init.os.path.isfile')
@patch('freezer_api.cmd.db_init.os.getcwd')
def test_find_config_file_returns_file_in_cwd(self, mock_os_getcwd, mock_os_path_isfile):
mock_os_getcwd.return_value = '/home/woohoo'
mock_os_path_isfile.return_value = True
res = find_config_file()
self.assertEquals('/home/woohoo/freezer-api.conf', res)
@patch('freezer_api.cmd.db_init.os.path.isfile')
@patch('freezer_api.cmd.db_init.os.getcwd')
def test_find_config_file_returns_defaultfile(self, mock_os_getcwd, mock_os_path_isfile):
mock_os_getcwd.return_value = '/home/woohoo'
mock_os_path_isfile.side_effect = [False, True, False]
res = find_config_file()
self.assertEquals(DEFAULT_CONF_PATH, res)
@patch('freezer_api.cmd.db_init.ConfigParser.ConfigParser')
def test_parse_config_file_return_config_file_params(self, mock_ConfigParser):
mock_config = Mock()
mock_ConfigParser.return_value = mock_config
mock_config.get.side_effect = lambda *x: {('storage', 'endpoint'): 'http://iperuranio:1999',
('storage', 'index'): 'ohyes',
('storage', 'number_of_replicas'): '10'}[x]
host, port, index, replicas = parse_config_file('dontcare')
self.assertEquals(host, 'iperuranio')
self.assertEquals(port, 1999)
self.assertEquals(index, 'ohyes')
self.assertEquals(replicas, 10)
@patch('freezer_api.cmd.db_init.parse_config_file')
def test_get_db_params_returns_args_parameters(self, mock_parse_config_file):
mock_parse_config_file.return_value = (None, None, None, None )
mock_args = Mock()
mock_args.host = 'pumpkin'
mock_args.port = 12345
mock_args.index = 'ciccio'
elasticsearch_url, elasticsearch_index, elasticsearch_replicas = get_db_params(mock_args)
self.assertEquals(elasticsearch_url, 'http://pumpkin:12345')
self.assertEquals(elasticsearch_index, 'ciccio')
@patch('freezer_api.cmd.db_init.ElastichsearchEngine')
@patch('freezer_api.cmd.db_init.get_db_params')
@patch('freezer_api.cmd.db_init.get_args')
def test_main_calls_esmanager_put_mappings_with_mappings(self, mock_get_args, mock_get_db_params,
mock_ElastichsearchEngine):
mock_get_args.return_value = self.mock_args
mock_get_db_params.return_value = 'url', 'index', 0
mock_es_manager = Mock()
mock_es_manager.put_mappings.return_value = os.EX_OK
mock_ElastichsearchEngine.return_value = mock_es_manager
res = main()
self.assertEquals(res, os.EX_OK)
mappings = db_mappings.get_mappings()
mock_es_manager.put_mappings.assert_called_with(mappings)
@patch('freezer_api.cmd.db_init.ElastichsearchEngine')
@patch('freezer_api.cmd.db_init.get_db_params')
@patch('freezer_api.cmd.db_init.get_args')
def test_main_return_EX_DATAERR_exitcode_on_error(self, mock_get_args, mock_get_db_params,
mock_ElastichsearchEngine):
mock_get_args.return_value = self.mock_args
mock_get_db_params.return_value = 'url', 'index', 0
mock_es_manager = Mock()
mock_ElastichsearchEngine.return_value = mock_es_manager
mock_es_manager.put_mappings.side_effect = Exception('test error')
res = main()
self.assertEquals(res, os.EX_DATAERR)