def test_armada_override_exception(self, mock_tiller, mock_source): """Test Armada checks with invalid chart override.""" yaml_documents = list(yaml.safe_load_all(TEST_YAML)) override = ('chart:example-chart-2:name=' 'overridden', ) error_re = ('is not a valid override statement') with self.assertRaisesRegexp(InvalidOverrideValueException, error_re): armada.Armada(yaml_documents, set_ovr=override)
def test_pre_flight_ops(self, MockChartDownload): """Test pre-flight checks and operations.""" yaml_documents = list(yaml.safe_load_all(TEST_YAML)) m_helm = mock.Mock() armada_obj = armada.Armada(yaml_documents, m_helm) self._test_pre_flight_ops(armada_obj, MockChartDownload) MockChartDownload.return_value.get_chart.assert_called()
def test_armada_manifest_exception_override_none(self, mock_source): """Test Armada checks with invalid manifest.""" yaml_documents = list(yaml.safe_load_all(TEST_YAML)) example_document = [ d for d in yaml_documents if d['metadata']['name'] == 'example-chart-4' ][0] del example_document['data']['release'] error_re = ('Invalid document .*') with self.assertRaisesRegexp(InvalidManifestException, error_re): armada.Armada(yaml_documents, mock.MagicMock(), set_ovr=None)
def test_pre_flight_ops(self, mock_tiller, mock_source): """Test pre-flight checks and operations.""" yaml_documents = list(yaml.safe_load_all(TEST_YAML)) armada_obj = armada.Armada(yaml_documents) # Mock methods called by `pre_flight_ops()`. mock_tiller.tiller_status.return_value = True mock_source.git_clone.return_value = CHART_SOURCES[0][0] self._test_pre_flight_ops(armada_obj) mock_tiller.assert_called_once_with(tiller_host=None, tiller_namespace='kube-system', tiller_port=44134) mock_source.git_clone.assert_called_once_with( 'git://github.com/dummy/armada', 'master', None)
def test_pre_flight_ops(self, mock_source): """Test pre-flight checks and operations.""" yaml_documents = list(yaml.safe_load_all(TEST_YAML)) m_tiller = mock.Mock() m_tiller.tiller_status.return_value = True armada_obj = armada.Armada(yaml_documents, m_tiller) # Mock methods called by `pre_flight_ops()`. mock_source.git_clone.return_value = CHART_SOURCES[0][0] self._test_pre_flight_ops(armada_obj) mock_source.git_clone.assert_called_once_with( 'git://github.com/dummy/armada', 'master', auth_method=None, proxy_server=None)
def test_post_flight_ops(self, mock_tiller, mock_source): """Test post-flight operations.""" yaml_documents = list(yaml.safe_load_all(TEST_YAML)) armada_obj = armada.Armada(yaml_documents) # Mock methods called by `pre_flight_ops()`. mock_tiller.tiller_status.return_value = True mock_source.git_clone.return_value = CHART_SOURCES[0][0] self._test_pre_flight_ops(armada_obj) armada_obj.post_flight_ops() for group in armada_obj.manifest['armada']['chart_groups']: for counter, chart in enumerate(group.get('chart_group')): if chart.get('chart').get('source').get('type') == 'git': mock_source.source_cleanup.assert_called_with( CHART_SOURCES[counter][0])
def test_post_flight_ops(self, MockChartDownload): """Test post-flight operations.""" yaml_documents = list(yaml.safe_load_all(TEST_YAML)) # Mock methods called by `pre_flight_ops()`. m_helm = mock.Mock() armada_obj = armada.Armada(yaml_documents, m_helm) self._test_pre_flight_ops(armada_obj, MockChartDownload) armada_obj.post_flight_ops() for group in armada_obj.manifest['data']['chart_groups']: for counter, chart in enumerate( group.get(const.KEYWORD_DATA).get(const.KEYWORD_CHARTS)): if chart.get( const.KEYWORD_DATA).get('source').get('type') == 'git': MockChartDownload.return_value.cleanup.assert_called_with()
def test_install(self, mock_tiller, mock_chartbuilder, mock_pre_flight, mock_post_flight): '''Test install functionality from the sync() method''' # Instantiate Armada object. yaml_documents = list(yaml.safe_load_all(TEST_YAML)) armada_obj = armada.Armada(yaml_documents) charts = armada_obj.manifest['armada']['chart_groups'][0][ 'chart_group'] chart_1 = charts[0]['chart'] chart_2 = charts[1]['chart'] # Mock irrelevant methods called by `armada.sync()`. mock_tiller.list_charts.return_value = [] mock_chartbuilder.get_source_path.return_value = None mock_chartbuilder.get_helm_chart.return_value = None armada_obj.sync() # Check params that should be passed to `tiller.install_release()`. method_calls = [ mock.call( mock_chartbuilder().get_helm_chart(), "{}-{}".format(armada_obj.manifest['armada']['release_prefix'], chart_1['release']), chart_1['namespace'], dry_run=armada_obj.dry_run, values=yaml.safe_dump(chart_1['values']), timeout=10, wait=True), mock.call( mock_chartbuilder().get_helm_chart(), "{}-{}".format(armada_obj.manifest['armada']['release_prefix'], chart_2['release']), chart_2['namespace'], dry_run=armada_obj.dry_run, values=yaml.safe_dump(chart_2['values']), timeout=10, wait=True) ] mock_tiller.return_value.install_release.assert_has_calls(method_calls)
def _do_test(mock_test_release_for_success, mock_tiller, mock_chartbuilder, mock_pre_flight, mock_post_flight): # Instantiate Armada object. yaml_documents = list(yaml.safe_load_all(TEST_YAML)) armada_obj = armada.Armada(yaml_documents) armada_obj.get_diff = mock.Mock() chart_group = armada_obj.manifest['armada']['chart_groups'][0] charts = chart_group['chart_group'] cg_test_all_charts = chart_group.get('test_charts', True) m_tiller = mock_tiller.return_value m_tiller.list_charts.return_value = known_releases if test_failure_to_run: def fail(tiller, release, timeout=None, cleanup=False): status = AttrDict( **{'info': AttrDict(**{'Description': 'Failed'})}) raise tiller_exceptions.ReleaseException( release, status, 'Test') mock_test_release_for_success.side_effect = fail else: mock_test_release_for_success.return_value = test_success # Stub out irrelevant methods called by `armada.sync()`. mock_chartbuilder.get_source_path.return_value = None mock_chartbuilder.get_helm_chart.return_value = None # Simulate chart diff, upgrade should only happen if non-empty. armada_obj.get_diff.return_value = diff armada_obj.sync() expected_install_release_calls = [] expected_update_release_calls = [] expected_uninstall_release_calls = [] expected_test_release_for_success_calls = [] for c in charts: chart = c['chart'] release = chart['release'] prefix = armada_obj.manifest['armada']['release_prefix'] release_name = release_prefixer(prefix, release) # Simplified check because the actual code uses logical-or's # multiple conditions, so this is enough. this_chart_should_wait = chart['wait']['timeout'] > 0 expected_apply = True if release_name not in [x[0] for x in known_releases]: expected_install_release_calls.append( mock.call(mock_chartbuilder().get_helm_chart(), "{}-{}".format( armada_obj.manifest['armada'] ['release_prefix'], chart['release']), chart['namespace'], values=yaml.safe_dump(chart['values']), wait=this_chart_should_wait, timeout=chart['wait']['timeout'])) else: target_release = None for known_release in known_releases: if known_release[0] == release_name: target_release = known_release break if target_release: status = target_release[4] if status == const.STATUS_FAILED: protected = chart.get('protected', {}) if not protected: expected_uninstall_release_calls.append( mock.call(release_name)) expected_install_release_calls.append( mock.call( mock_chartbuilder().get_helm_chart(), "{}-{}".format( armada_obj.manifest['armada'] ['release_prefix'], chart['release']), chart['namespace'], values=yaml.safe_dump(chart['values']), wait=this_chart_should_wait, timeout=chart['wait']['timeout'])) else: p_continue = protected.get( 'continue_processing', False) if p_continue: continue else: break if status == const.STATUS_DEPLOYED: if not diff: expected_apply = False else: upgrade = chart.get('upgrade', {}) disable_hooks = upgrade.get('no_hooks', False) force = upgrade.get('force', False) recreate_pods = upgrade.get( 'recreate_pods', False) expected_update_release_calls.append( mock.call( mock_chartbuilder().get_helm_chart(), "{}-{}".format( armada_obj.manifest['armada'] ['release_prefix'], chart['release']), chart['namespace'], pre_actions={}, post_actions={}, disable_hooks=disable_hooks, force=force, recreate_pods=recreate_pods, values=yaml.safe_dump(chart['values']), wait=this_chart_should_wait, timeout=chart['wait']['timeout'])) test_chart_override = chart.get('test') # Use old default value when not using newer `test` key test_cleanup = True if test_chart_override is None: test_this_chart = cg_test_all_charts elif isinstance(test_chart_override, bool): test_this_chart = test_chart_override else: test_this_chart = test_chart_override.get('enabled', True) test_cleanup = test_chart_override.get('options', {}).get( 'cleanup', False) if test_this_chart and expected_apply: expected_test_release_for_success_calls.append( mock.call(m_tiller, release_name, timeout=mock.ANY, cleanup=test_cleanup)) # Verify that at least 1 release is either installed or updated. self.assertTrue( len(expected_install_release_calls) >= 1 or len(expected_update_release_calls) >= 1) # Verify that the expected number of non-deployed releases are # installed with expected arguments. self.assertEqual(len(expected_install_release_calls), m_tiller.install_release.call_count) m_tiller.install_release.assert_has_calls( expected_install_release_calls) # Verify that the expected number of deployed releases are # updated with expected arguments. self.assertEqual(len(expected_update_release_calls), m_tiller.update_release.call_count) m_tiller.update_release.assert_has_calls( expected_update_release_calls) # Verify that the expected number of deployed releases are # uninstalled with expected arguments. self.assertEqual(len(expected_uninstall_release_calls), m_tiller.uninstall_release.call_count) m_tiller.uninstall_release.assert_has_calls( expected_uninstall_release_calls) # Verify that the expected number of deployed releases are # tested with expected arguments. self.assertEqual(len(expected_test_release_for_success_calls), mock_test_release_for_success.call_count) mock_test_release_for_success.assert_has_calls( expected_test_release_for_success_calls)
def _do_test(mock_test, mock_chartbuilder, MockChartDownload, mock_post_flight): MockChartDownload.return_value.get_chart.side_effect = \ set_source_dir # Instantiate Armada object. yaml_documents = list(yaml.safe_load_all(TEST_YAML)) m_helm = mock.MagicMock() armada_obj = armada.Armada(yaml_documents, m_helm) prefix = armada_obj.manifest['data']['release_prefix'] def release_metadata(release_id, **kwargs): try: return next(r for r in known_releases if release_id.name == r['name'] and release_id.namespace == r['namespace']) except StopIteration: return None m_helm.release_metadata.side_effect = release_metadata armada_obj.chart_deploy.get_diff = mock.Mock() cg = armada_obj.manifest['data']['chart_groups'][0] chart_group = cg['data'] charts = chart_group['chart_group'] cg_test_all_charts = chart_group.get('test_charts') mock_test_release = mock_test.return_value.test_release if test_failure_to_run: mock_test_release.side_effect = Exception('test failed to run') else: if not test_success: mock_test_release.side_effect = Exception('test failed') mock_test.return_value.timeout = const.DEFAULT_TEST_TIMEOUT # Stub out irrelevant methods called by `armada.sync()`. mock_chartbuilder.get_helm_chart.return_value = None # Simulate chart diff, upgrade should only happen if non-empty. armada_obj.chart_deploy.get_diff.return_value = diff armada_obj.sync() expected_install_release_calls = [] expected_upgrade_release_calls = [] expected_uninstall_release_calls = [] expected_test_constructor_calls = [] for c in charts: chart = c['data'] release = chart['release'] release_name = release_prefixer(prefix, release) release_id = helm.HelmReleaseId(chart['namespace'], release_name) source_dir = chart['source_dir'] source_directory = os.path.join(*source_dir) # Simplified check because the actual code uses logical-or's # multiple conditions, so this is enough. native_wait_enabled = (chart['wait'].get('native', {}).get( 'enabled', True)) if release_name not in [x['name'] for x in known_releases]: expected_install_release_calls.append( mock.call(source_directory, release_id, values=chart['values'], wait=native_wait_enabled, timeout=mock.ANY)) else: target_release = None for known_release in known_releases: if known_release['name'] == release_name: target_release = known_release break if target_release: status = get_release_status(target_release) if status == helm.STATUS_FAILED: protected = chart.get('protected', {}) if not protected: expected_uninstall_release_calls.append( mock.call( release_id, purge=True, timeout=const.DEFAULT_DELETE_TIMEOUT)) expected_install_release_calls.append( mock.call(source_directory, release_id, values=chart['values'], wait=native_wait_enabled, timeout=mock.ANY)) else: p_continue = protected.get( 'continue_processing', False) if p_continue: continue else: if chart_group['sequenced']: break if status == helm.STATUS_DEPLOYED: if diff: upgrade = chart.get('upgrade', {}) disable_hooks = upgrade.get('no_hooks', False) options = upgrade.get('options', {}) force = options.get('force', False) expected_upgrade_release_calls.append( mock.call(source_directory, release_id, disable_hooks=disable_hooks, force=force, values=chart['values'], wait=native_wait_enabled, timeout=mock.ANY)) expected_test_constructor_calls.append( mock.call(chart, release_id, m_helm, cg_test_charts=cg_test_all_charts)) any_order = not chart_group['sequenced'] # Verify that at least 1 release is either installed or updated. self.assertTrue( len(expected_install_release_calls) >= 1 or len(expected_upgrade_release_calls) >= 1) # Verify that the expected number of non-deployed releases are # installed with expected arguments. self.assertEqual(len(expected_install_release_calls), m_helm.install_release.call_count) m_helm.install_release.assert_has_calls( expected_install_release_calls, any_order=any_order) # Verify that the expected number of deployed releases are # updated with expected arguments. self.assertEqual(len(expected_upgrade_release_calls), m_helm.upgrade_release.call_count) m_helm.upgrade_release.assert_has_calls( expected_upgrade_release_calls, any_order=any_order) # Verify that the expected number of deployed releases are # uninstalled with expected arguments. self.assertEqual(len(expected_uninstall_release_calls), m_helm.uninstall_release.call_count) m_helm.uninstall_release.assert_has_calls( expected_uninstall_release_calls, any_order=any_order) # Verify that the expected number of deployed releases are # tested with expected arguments. self.assertEqual(len(expected_test_constructor_calls), mock_test.call_count) mock_test.assert_has_calls(expected_test_constructor_calls, any_order=True)
def _do_test(mock_test, mock_chartbuilder, mock_pre_flight, mock_post_flight): # Instantiate Armada object. yaml_documents = list(yaml.safe_load_all(TEST_YAML)) m_tiller = mock.MagicMock() m_tiller.list_releases.return_value = known_releases armada_obj = armada.Armada(yaml_documents, m_tiller) armada_obj.chart_deploy.get_diff = mock.Mock() chart_group = armada_obj.manifest['armada']['chart_groups'][0] charts = chart_group['chart_group'] cg_test_all_charts = chart_group.get('test_charts') mock_test_release = mock_test.return_value.test_release_for_success if test_failure_to_run: def fail(tiller, release, timeout=None, cleanup=False): status = AttrDict( **{'info': AttrDict(**{'Description': 'Failed'})}) raise tiller_exceptions.ReleaseException( release, status, 'Test') mock_test_release.side_effect = fail else: mock_test_release.return_value = test_success # Stub out irrelevant methods called by `armada.sync()`. mock_chartbuilder.get_source_path.return_value = None mock_chartbuilder.get_helm_chart.return_value = None # Simulate chart diff, upgrade should only happen if non-empty. armada_obj.chart_deploy.get_diff.return_value = diff armada_obj.sync() expected_install_release_calls = [] expected_update_release_calls = [] expected_uninstall_release_calls = [] expected_test_constructor_calls = [] for c in charts: chart = c['chart'] release = chart['release'] prefix = armada_obj.manifest['armada']['release_prefix'] release_name = release_prefixer(prefix, release) # Simplified check because the actual code uses logical-or's # multiple conditions, so this is enough. native_wait_enabled = (chart['wait'].get('native', {}).get( 'enabled', True)) if release_name not in [x.name for x in known_releases]: expected_install_release_calls.append( mock.call( mock_chartbuilder().get_helm_chart(), "{}-{}".format( armada_obj.manifest['armada'] ['release_prefix'], chart['release']), chart['namespace'], values=yaml.safe_dump(chart['values']), wait=native_wait_enabled, timeout=mock.ANY)) else: target_release = None for known_release in known_releases: if known_release.name == release_name: target_release = known_release break if target_release: status = get_release_status(target_release) if status == const.STATUS_FAILED: protected = chart.get('protected', {}) if not protected: expected_uninstall_release_calls.append( mock.call( release_name, purge=True, timeout=const.DEFAULT_DELETE_TIMEOUT)) expected_install_release_calls.append( mock.call( mock_chartbuilder().get_helm_chart(), "{}-{}".format( armada_obj.manifest['armada'] ['release_prefix'], chart['release']), chart['namespace'], values=yaml.safe_dump(chart['values']), wait=native_wait_enabled, timeout=mock.ANY)) else: p_continue = protected.get( 'continue_processing', False) if p_continue: continue else: if chart_group['sequenced']: break if status == const.STATUS_DEPLOYED: if diff: upgrade = chart.get('upgrade', {}) disable_hooks = upgrade.get('no_hooks', False) options = upgrade.get('options', {}) force = options.get('force', False) recreate_pods = options.get( 'recreate_pods', False) expected_update_release_calls.append( mock.call( mock_chartbuilder().get_helm_chart(), "{}-{}".format( armada_obj.manifest['armada'] ['release_prefix'], chart['release']), chart['namespace'], pre_actions={}, post_actions={}, disable_hooks=disable_hooks, force=force, recreate_pods=recreate_pods, values=yaml.safe_dump(chart['values']), wait=native_wait_enabled, timeout=mock.ANY)) expected_test_constructor_calls.append( mock.call( chart, release_name, m_tiller, cg_test_charts=cg_test_all_charts)) any_order = not chart_group['sequenced'] # Verify that at least 1 release is either installed or updated. self.assertTrue( len(expected_install_release_calls) >= 1 or len(expected_update_release_calls) >= 1) # Verify that the expected number of non-deployed releases are # installed with expected arguments. self.assertEqual( len(expected_install_release_calls), m_tiller.install_release.call_count) m_tiller.install_release.assert_has_calls( expected_install_release_calls, any_order=any_order) # Verify that the expected number of deployed releases are # updated with expected arguments. self.assertEqual( len(expected_update_release_calls), m_tiller.update_release.call_count) m_tiller.update_release.assert_has_calls( expected_update_release_calls, any_order=any_order) # Verify that the expected number of deployed releases are # uninstalled with expected arguments. self.assertEqual( len(expected_uninstall_release_calls), m_tiller.uninstall_release.call_count) m_tiller.uninstall_release.assert_has_calls( expected_uninstall_release_calls, any_order=any_order) # Verify that the expected number of deployed releases are # tested with expected arguments. self.assertEqual( len(expected_test_constructor_calls), mock_test.call_count) mock_test.assert_has_calls( expected_test_constructor_calls, any_order=True)