# -*- coding: utf-8 -*- ''' :codauthor: :email:`Mike Place ` :copyright: © 2013 by the SaltStack Team, see AUTHORS for more details. :license: Apache 2.0, see LICENSE for more details. ''' # Import python libs import os import shutil # Import Salt Testing libs from salttesting import skipIf, TestCase from salttesting.helpers import ensure_in_syspath from salttesting.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch, call ensure_in_syspath('../') # Import salt libs import integration import salt.overstate from salt.config import master_config OVERSTATE_SLS = { 'mysql': { 'match': 'db*', 'sls': { 'mysql.server': 'drbd' } }, 'webservers': { 'match': 'web*', 'require': ['mysql'] }, 'all': { 'match': '*', 'require': { 'mysql': 'webservers' } } } @skipIf(NO_MOCK, NO_MOCK_REASON) class OverstateTestCase(TestCase, integration.AdaptedConfigurationTestCaseMixIn): def setUp(self): self.master_config = master_config(self.get_config_file_path('master')) for entry in ('root_dir', 'cachedir'): if not os.path.isdir(self.master_config[entry]): os.makedirs(self.master_config[entry]) def tearDown(self): if os.path.isdir(self.master_config['root_dir']): shutil.rmtree(self.master_config['root_dir']) @patch('salt.client.LocalClient.cmd') def test__stage_list(self, local_client_mock): overstate = salt.overstate.OverState(self.master_config) overstate._stage_list(['test1', 'test2']) local_client_mock.assert_called_with('test1 or test2', 'test.ping', expr_form='compound') # @skipIf(True, "Do not run this test! It exposes a memory leak inside pyyaml: https://bitbucket.org/xi/pyyaml/issue/24") # def test__names(self): # y = 'a' # mopen = mock_open(read_data=y) # with patch('salt.utils.fopen', mopen, create=True): # overstate = salt.overstate.OverState(self.master_config, overstate='a') def test__names(self): overstate = salt.overstate.OverState(self.master_config) overstate.over = overstate._OverState__sort_stages(OVERSTATE_SLS) self.assertEqual( set(['webservers', 'all', 'mysql']), overstate._names() ) def test_get_stage(self): overstate = salt.overstate.OverState(self.master_config) overstate.over = overstate._OverState__sort_stages(OVERSTATE_SLS) ret = overstate.get_stage('mysql') self.assertDictEqual({'mysql': {'match': 'db*', 'sls': {'mysql.server': 'drbd'}}}, ret) @patch('salt.overstate.OverState.call_stage') def test_stages(self, call_stage_mock): ''' This is a very basic test and needs expansion, since call_stage is mocked! ''' overstate = salt.overstate.OverState(self.master_config) overstate.over = overstate._OverState__sort_stages(OVERSTATE_SLS) overstate.stages() expected_calls = [call('all', {'require': {'mysql': 'webservers'}, 'match': '*'}), call('mysql', {'match': 'db*', 'sls': {'mysql.server': 'drbd'}}), call('webservers', {'require': ['mysql'], 'match': 'web*'})] call_stage_mock.assert_has_calls(expected_calls, any_order=False) def test_verify_stage(self): overstate = salt.overstate.OverState(self.master_config) test_stage = {'require': {'webservers': 'mysql'}, 'match': '*'} ret = overstate.verify_stage(test_stage) self.assertDictEqual(test_stage, test_stage) def test_verify_fail(self): overstate = salt.overstate.OverState(self.master_config) test_stage = {'require': {'webservers': 'mysql'}} ret = overstate.verify_stage(test_stage) self.assertIn('No "match" argument in stage.', ret) @patch('salt.utils.check_state_result') def test__check_results_for_failed_prereq(self, check_state_result_mock): check_state_result_mock.return_value = True overstate = salt.overstate.OverState(self.master_config) overstate.over_run = {'mysql': {'minion1': { 'ret': { 'result': True, 'comment': 'Victory is ours!', 'name': 'mysql', 'changes': {}, '__run_num__': 0, }, 'fun': MagicMock(name='Mock of minion1 mysql func'), 'retcode': 0, 'success': False } } } ret = overstate._check_results('mysql', 'all', {}, {'all': {}}) self.assertDictEqual({'all': {'req_|-fail_|-fail_|-None': {'fun': 'req.fail', 'ret': {'__run_num__': 0, 'changes': {}, 'comment': 'Requisite mysql failed for stage on minion minion1', 'name': 'Requisite Failure', 'result': False}, 'retcode': 254, 'success': False}}}, {'all': {'req_|-fail_|-fail_|-None': {'fun': 'req.fail', 'ret': {'__run_num__': 0, 'changes': {}, 'comment': 'Requisite mysql failed for stage on minion minion1', 'name': 'Requisite Failure', 'result': False}, 'retcode': 254, 'success': False}}}, ret) @patch('salt.utils.check_state_result') def test__check_results_for_successful_prereq(self, check_state_result_mock): check_state_result_mock.return_value = True overstate = salt.overstate.OverState(self.master_config) overstate.over_run = {'mysql': {'minion1': { 'ret': { 'result': True, 'comment': 'Victory is ours!', 'name': 'mysql', 'changes': {}, '__run_num__': 0, }, 'fun': MagicMock(name='Mock of minion1 mysql func'), 'retcode': 0, 'success': True } } } ret = overstate._check_results('mysql', 'all', {}, {'all': {}}) self.assertEqual(ret, ({}, {'all': {}})) # @patch('salt.overstate.OverState.call_stage') # def test_call_stage(self, call_stage_mock): # overstate = salt.overstate.OverState(self.master_config) # overstate.over = overstate._OverState__sort_stages(OVERSTATE_SLS) # overstate.call_stage('all', {'require': {'webservers': 'mysql'}, 'match': '*'}) # overstate.call_stage('mysql', {'match': 'db*', 'sls': {'drbb': 'mysql.server'}}) # overstate.call_stage({'require': ['mysql'], 'match': 'web*'})