Merge "Separate out test_parse_to_value_exception()"
[yardstick.git] / yardstick / tests / unit / benchmark / core / test_task.py
index bac035f..e1414c2 100644 (file)
@@ -7,18 +7,30 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
+import copy
+import io
+import logging
 import os
+import sys
 
 import mock
+import six
+from six.moves import builtins
 import unittest
+import uuid
 
+from yardstick.benchmark.contexts import base
+from yardstick.benchmark.contexts import dummy
 from yardstick.benchmark.core import task
 from yardstick.common import constants as consts
+from yardstick.common import exceptions
+from yardstick.common import task_template
+from yardstick.common import utils
 
 
 class TaskTestCase(unittest.TestCase):
 
-    @mock.patch.object(task, 'Context')
+    @mock.patch.object(base, 'Context')
     def test_parse_nodes_with_context_same_context(self, mock_context):
         scenario_cfg = {
             "nodes": {
@@ -48,11 +60,18 @@ class TaskTestCase(unittest.TestCase):
     def test__do_output(self, mock_dispatcher):
         t = task.Task()
         output_config = {"DEFAULT": {"dispatcher": "file, http"}}
-        mock_dispatcher.get = mock.MagicMock(return_value=[mock.MagicMock(),
-                                                           mock.MagicMock()])
-        self.assertEqual(None, t._do_output(output_config, {}))
 
-    @mock.patch.object(task, 'Context')
+        dispatcher1 = mock.MagicMock()
+        dispatcher1.__dispatcher_type__ = 'file'
+
+        dispatcher2 = mock.MagicMock()
+        dispatcher2.__dispatcher_type__ = 'http'
+
+        mock_dispatcher.get = mock.MagicMock(return_value=[dispatcher1,
+                                                           dispatcher2])
+        self.assertIsNone(t._do_output(output_config, {}))
+
+    @mock.patch.object(base, 'Context')
     def test_parse_networks_from_nodes(self, mock_context):
         nodes = {
             'node1': {
@@ -116,7 +135,7 @@ class TaskTestCase(unittest.TestCase):
         self.assertEqual(mock_context.get_network.call_count, expected_get_network_calls)
         self.assertDictEqual(networks, expected)
 
-    @mock.patch.object(task, 'Context')
+    @mock.patch.object(base, 'Context')
     @mock.patch.object(task, 'base_runner')
     def test_run(self, mock_base_runner, *args):
         scenario = {
@@ -137,7 +156,32 @@ class TaskTestCase(unittest.TestCase):
         runner.get_result.return_value = []
         mock_base_runner.Runner.get.return_value = runner
         t._run([scenario], False, "yardstick.out")
-        self.assertTrue(runner.run.called)
+        runner.run.assert_called_once()
+
+    @mock.patch.object(base, 'Context')
+    @mock.patch.object(task, 'base_runner')
+    def test_run_ProxDuration(self, mock_base_runner, *args):
+        scenario = {
+            'host': 'athena.demo',
+            'target': 'ares.demo',
+            'runner': {
+                'duration': 60,
+                'interval': 1,
+                'sampled': 'yes',
+                'confirmation': 1,
+                'type': 'ProxDuration'
+            },
+            'type': 'Ping'
+        }
+
+        t = task.Task()
+        runner = mock.Mock()
+        runner.join.return_value = 0
+        runner.get_output.return_value = {}
+        runner.get_result.return_value = []
+        mock_base_runner.Runner.get.return_value = runner
+        t._run([scenario], False, "yardstick.out")
+        runner.run.assert_called_once()
 
     @mock.patch.object(os, 'environ')
     def test_check_precondition(self, mock_os_environ):
@@ -167,7 +211,6 @@ class TaskTestCase(unittest.TestCase):
                          'tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml'))
         self.assertEqual(task_files[1], self.change_to_abspath(
                          'tests/opnfv/test_cases/opnfv_yardstick_tc043.yaml'))
-
         self.assertIsNone(task_args[0])
         self.assertIsNone(task_args[1])
         self.assertIsNone(task_args_fnames[0])
@@ -249,34 +292,41 @@ class TaskTestCase(unittest.TestCase):
         actual_result = t._parse_options(options)
         self.assertEqual(expected_result, actual_result)
 
+    def test_parse_options_no_teardown(self):
+        options = {
+            'openstack': {
+                'EXTERNAL_NETWORK': '$network'
+            },
+            'nodes': ['node1', '$node'],
+            'host': '$host',
+            'contexts' : {'name': "my-context",
+                          'no_teardown': True}
+        }
 
-    def test_change_server_name_host_str(self):
-        scenario = {'host': 'demo'}
-        suffix = '-8'
-        task.change_server_name(scenario, suffix)
-        self.assertEqual('demo-8', scenario['host'])
-
-    def test_change_server_name_host_dict(self):
-        scenario = {'host': {'name': 'demo'}}
-        suffix = '-8'
-        task.change_server_name(scenario, suffix)
-        self.assertEqual('demo-8', scenario['host']['name'])
+        t = task.Task()
+        t.outputs = {
+            'network': 'ext-net',
+            'node': 'node2',
+            'host': 'server.yardstick'
+        }
 
-    def test_change_server_name_target_str(self):
-        scenario = {'target': 'demo'}
-        suffix = '-8'
-        task.change_server_name(scenario, suffix)
-        self.assertEqual('demo-8', scenario['target'])
+        expected_result = {
+            'openstack': {
+                'EXTERNAL_NETWORK': 'ext-net'
+            },
+            'nodes': ['node1', 'node2'],
+            'host': 'server.yardstick',
+            'contexts': {'name': 'my-context',
+                         'no_teardown': True,
+                        }
+        }
 
-    def test_change_server_name_target_dict(self):
-        scenario = {'target': {'name': 'demo'}}
-        suffix = '-8'
-        task.change_server_name(scenario, suffix)
-        self.assertEqual('demo-8', scenario['target']['name'])
+        actual_result = t._parse_options(options)
+        self.assertEqual(expected_result, actual_result)
 
-    @mock.patch('six.moves.builtins.open', side_effect=mock.mock_open())
+    @mock.patch.object(builtins, 'open', side_effect=mock.mock_open())
     @mock.patch.object(task, 'utils')
-    @mock.patch('logging.root')
+    @mock.patch.object(logging, 'root')
     def test_set_log(self, mock_logging_root, *args):
         task_obj = task.Task()
         task_obj.task_id = 'task_id'
@@ -292,9 +342,258 @@ class TaskTestCase(unittest.TestCase):
         return os.path.join(consts.YARDSTICK_ROOT_PATH, filepath)
 
 
-def main():
-    unittest.main()
+class TaskParserTestCase(unittest.TestCase):
+
+    TASK = """
+{% set value1 = value1 or 'var1' %}
+{% set value2 = value2 or 'var2' %}
+key1: {{ value1 }}
+key2:
+    - {{ value2 }}"""
+
+    TASK_RENDERED_1 = u"""
+
+
+key1: var1
+key2:
+    - var2"""
+
+    TASK_RENDERED_2 = u"""
+
+
+key1: var3
+key2:
+    - var4"""
+
+    def setUp(self):
+        self.parser = task.TaskParser('fake/path')
+        self.scenario = {
+            'host': 'athena.demo',
+            'target': 'kratos.demo',
+            'targets': [
+                'ares.demo', 'mars.demo'
+                ],
+            'options': {
+                'server_name': {
+                    'host': 'jupiter.demo',
+                    'target': 'saturn.demo',
+                    },
+                },
+            'nodes': {
+                'tg__0': 'tg_0.demo',
+                'vnf__0': 'vnf_0.demo',
+                }
+            }
+
+    @staticmethod
+    def _remove_contexts():
+        for context in base.Context.list:
+            context._delete_context()
+        base.Context.list = []
+
+    def test__change_node_names(self):
+
+        ctx_attrs = {
+            'name': 'demo',
+            'task_id': '1234567890',
+            'servers': [
+                'athena', 'kratos',
+                'ares', 'mars',
+                'jupiter', 'saturn',
+                'tg_0', 'vnf_0'
+                ]
+            }
+
+        my_context = dummy.DummyContext()
+        self.addCleanup(self._remove_contexts)
+        my_context.init(ctx_attrs)
+
+        expected_scenario = {
+            'host': 'athena.demo-12345678',
+            'target': 'kratos.demo-12345678',
+            'targets': [
+                'ares.demo-12345678', 'mars.demo-12345678'
+                ],
+            'options': {
+                'server_name': {
+                    'host': 'jupiter.demo-12345678',
+                    'target': 'saturn.demo-12345678',
+                    },
+                },
+            'nodes': {
+                'tg__0': 'tg_0.demo-12345678',
+                'vnf__0': 'vnf_0.demo-12345678',
+                }
+            }
+
+        scenario = copy.deepcopy(self.scenario)
+
+        self.parser._change_node_names(scenario, [my_context])
+        self.assertEqual(scenario, expected_scenario)
+
+    def test__change_node_names_context_not_found(self):
+        scenario = copy.deepcopy(self.scenario)
+        self.assertRaises(exceptions.ScenarioConfigContextNameNotFound,
+                          self.parser._change_node_names,
+                          scenario, [])
+
+    def test__change_node_names_context_name_unchanged(self):
+        ctx_attrs = {
+            'name': 'demo',
+            'task_id': '1234567890',
+            'flags': {
+                'no_setup': True,
+                'no_teardown': True
+                }
+            }
+
+        my_context = dummy.DummyContext()
+        self.addCleanup(self._remove_contexts)
+        my_context.init(ctx_attrs)
 
+        scenario = copy.deepcopy(self.scenario)
+        expected_scenario = copy.deepcopy(self.scenario)
 
-if __name__ == '__main__':
-    main()
+        self.parser._change_node_names(scenario, [my_context])
+        self.assertEqual(scenario, expected_scenario)
+
+    def test__change_node_names_options_empty(self):
+        ctx_attrs = {
+            'name': 'demo',
+            'task_id': '1234567890'
+        }
+
+        my_context = dummy.DummyContext()
+        self.addCleanup(self._remove_contexts)
+        my_context.init(ctx_attrs)
+        scenario = copy.deepcopy(self.scenario)
+        scenario['options'] = None
+
+        self.parser._change_node_names(scenario, [my_context])
+        self.assertIsNone(scenario['options'])
+
+    def test__change_node_names_options_server_name_empty(self):
+        ctx_attrs = {
+            'name': 'demo',
+            'task_id': '1234567890'
+        }
+
+        my_context = dummy.DummyContext()
+        self.addCleanup(self._remove_contexts)
+        my_context.init(ctx_attrs)
+        scenario = copy.deepcopy(self.scenario)
+        scenario['options']['server_name'] = None
+
+        self.parser._change_node_names(scenario, [my_context])
+        self.assertIsNone(scenario['options']['server_name'])
+
+    def test__parse_tasks(self):
+        task_obj = task.Task()
+        _uuid = uuid.uuid4()
+        task_obj.task_id = _uuid
+        task_files = ['/directory/task_file_name.yml']
+        mock_parser = mock.Mock()
+        mock_parser.parse_task.return_value = {'rendered': 'File content'}
+        mock_args = mock.Mock()
+        mock_args.render_only = False
+
+        tasks = task_obj._parse_tasks(mock_parser, task_files, mock_args,
+                                      ['arg1'], ['file_arg1'])
+        self.assertEqual(
+            [{'rendered': 'File content', 'case_name': 'task_file_name'}],
+            tasks)
+        mock_parser.parse_task.assert_called_once_with(
+            _uuid, 'arg1', 'file_arg1')
+
+    @mock.patch.object(sys, 'exit')
+    @mock.patch.object(utils, 'write_file')
+    @mock.patch.object(utils, 'makedirs')
+    def test__parse_tasks_render_only(self, mock_makedirs, mock_write_file,
+                                      mock_exit):
+        task_obj = task.Task()
+        _uuid = uuid.uuid4()
+        task_obj.task_id = _uuid
+        task_files = ['/directory/task_file_name.yml']
+        mock_parser = mock.Mock()
+        mock_parser.parse_task.return_value = {'rendered': 'File content'}
+        mock_args = mock.Mock()
+        mock_args.render_only = '/output_directory'
+
+        task_obj._parse_tasks(mock_parser, task_files, mock_args,
+                              ['arg1'], ['file_arg1'])
+        mock_makedirs.assert_called_once_with('/output_directory')
+        mock_write_file.assert_called_once_with(
+            '/output_directory/000-task_file_name.yml', 'File content')
+        mock_exit.assert_called_once_with(0)
+
+    def test__render_task_no_args(self):
+        task_parser = task.TaskParser('task_file')
+        task_str = io.StringIO(six.text_type(self.TASK))
+        with mock.patch.object(six.moves.builtins, 'open',
+                               return_value=task_str) as mock_open:
+            parsed, rendered = task_parser._render_task(None, None)
+
+        self.assertEqual(self.TASK_RENDERED_1, rendered)
+        self.assertEqual({'key1': 'var1', 'key2': ['var2']}, parsed)
+        mock_open.assert_called_once_with('task_file')
+
+    def test__render_task_arguments(self):
+        task_parser = task.TaskParser('task_file')
+        task_str = io.StringIO(six.text_type(self.TASK))
+        with mock.patch.object(six.moves.builtins, 'open',
+                               return_value=task_str) as mock_open:
+            parsed, rendered = task_parser._render_task('value1: "var1"', None)
+
+        self.assertEqual(self.TASK_RENDERED_1, rendered)
+        self.assertEqual({'key1': 'var1', 'key2': ['var2']}, parsed)
+        mock_open.assert_called_once_with('task_file')
+
+    def test__render_task_file_arguments(self):
+        task_parser = task.TaskParser('task_file')
+        with mock.patch.object(six.moves.builtins, 'open') as mock_open:
+            mock_open.side_effect = (
+                io.StringIO(six.text_type('value2: var4')),
+                io.StringIO(six.text_type(self.TASK))
+            )
+            parsed, rendered = task_parser._render_task('value1: "var3"',
+                                                        'args_file')
+
+        self.assertEqual(self.TASK_RENDERED_2, rendered)
+        self.assertEqual({'key1': 'var3', 'key2': ['var4']}, parsed)
+        mock_open.assert_has_calls([mock.call('args_file'),
+                                    mock.call('task_file')])
+
+    @mock.patch.object(builtins, 'print')
+    def test__render_task_error_arguments(self, *args):
+        with self.assertRaises(exceptions.TaskRenderArgumentError):
+            task.TaskParser('task_file')._render_task('value1="var3"', None)
+
+    def test__render_task_error_task_file(self):
+        task_parser = task.TaskParser('task_file')
+        with mock.patch.object(six.moves.builtins, 'open') as mock_open:
+            mock_open.side_effect = (
+                io.StringIO(six.text_type('value2: var4')),
+                IOError()
+            )
+            with self.assertRaises(exceptions.TaskReadError):
+                task_parser._render_task('value1: "var3"', 'args_file')
+
+        mock_open.assert_has_calls([mock.call('args_file'),
+                                    mock.call('task_file')])
+
+    def test__render_task_render_error(self):
+        task_parser = task.TaskParser('task_file')
+        with mock.patch.object(six.moves.builtins, 'open') as mock_open, \
+                mock.patch.object(task_template.TaskTemplate, 'render',
+                                  side_effect=TypeError) as mock_render:
+            mock_open.side_effect = (
+                io.StringIO(six.text_type('value2: var4')),
+                io.StringIO(six.text_type(self.TASK))
+            )
+            with self.assertRaises(exceptions.TaskRenderError):
+                task_parser._render_task('value1: "var3"', 'args_file')
+
+        mock_open.assert_has_calls([mock.call('args_file'),
+                                    mock.call('task_file')])
+        mock_render.assert_has_calls(
+            [mock.call(self.TASK, value1='var3', value2='var4')])