Merge "Separate out test_parse_to_value_exception()"
[yardstick.git] / yardstick / tests / unit / benchmark / core / test_task.py
index 25a7a64..e1414c2 100644 (file)
@@ -8,20 +8,29 @@
 ##############################################################################
 
 import copy
 ##############################################################################
 
 import copy
+import io
+import logging
 import os
 import os
+import sys
 
 import mock
 
 import mock
+import six
+from six.moves import builtins
 import unittest
 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.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):
 
 
 
 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": {
     def test_parse_nodes_with_context_same_context(self, mock_context):
         scenario_cfg = {
             "nodes": {
@@ -60,9 +69,9 @@ class TaskTestCase(unittest.TestCase):
 
         mock_dispatcher.get = mock.MagicMock(return_value=[dispatcher1,
                                                            dispatcher2])
 
         mock_dispatcher.get = mock.MagicMock(return_value=[dispatcher1,
                                                            dispatcher2])
-        self.assertEqual(None, t._do_output(output_config, {}))
+        self.assertIsNone(t._do_output(output_config, {}))
 
 
-    @mock.patch.object(task, 'Context')
+    @mock.patch.object(base, 'Context')
     def test_parse_networks_from_nodes(self, mock_context):
         nodes = {
             'node1': {
     def test_parse_networks_from_nodes(self, mock_context):
         nodes = {
             'node1': {
@@ -126,7 +135,7 @@ class TaskTestCase(unittest.TestCase):
         self.assertEqual(mock_context.get_network.call_count, expected_get_network_calls)
         self.assertDictEqual(networks, expected)
 
         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 = {
     @mock.patch.object(task, 'base_runner')
     def test_run(self, mock_base_runner, *args):
         scenario = {
@@ -147,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")
         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):
 
     @mock.patch.object(os, 'environ')
     def test_check_precondition(self, mock_os_environ):
@@ -177,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'))
                          '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])
         self.assertIsNone(task_args[0])
         self.assertIsNone(task_args[1])
         self.assertIsNone(task_args_fnames[0])
@@ -259,9 +292,41 @@ class TaskTestCase(unittest.TestCase):
         actual_result = t._parse_options(options)
         self.assertEqual(expected_result, actual_result)
 
         actual_result = t._parse_options(options)
         self.assertEqual(expected_result, actual_result)
 
-    @mock.patch('six.moves.builtins.open', side_effect=mock.mock_open())
+    def test_parse_options_no_teardown(self):
+        options = {
+            'openstack': {
+                'EXTERNAL_NETWORK': '$network'
+            },
+            'nodes': ['node1', '$node'],
+            'host': '$host',
+            'contexts' : {'name': "my-context",
+                          'no_teardown': True}
+        }
+
+        t = task.Task()
+        t.outputs = {
+            'network': 'ext-net',
+            'node': 'node2',
+            'host': 'server.yardstick'
+        }
+
+        expected_result = {
+            'openstack': {
+                'EXTERNAL_NETWORK': 'ext-net'
+            },
+            'nodes': ['node1', 'node2'],
+            'host': 'server.yardstick',
+            'contexts': {'name': 'my-context',
+                         'no_teardown': True,
+                        }
+        }
+
+        actual_result = t._parse_options(options)
+        self.assertEqual(expected_result, actual_result)
+
+    @mock.patch.object(builtins, 'open', side_effect=mock.mock_open())
     @mock.patch.object(task, 'utils')
     @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'
     def test_set_log(self, mock_logging_root, *args):
         task_obj = task.Task()
         task_obj.task_id = 'task_id'
@@ -279,6 +344,27 @@ class TaskTestCase(unittest.TestCase):
 
 class TaskParserTestCase(unittest.TestCase):
 
 
 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 = {
     def setUp(self):
         self.parser = task.TaskParser('fake/path')
         self.scenario = {
@@ -299,6 +385,12 @@ class TaskParserTestCase(unittest.TestCase):
                 }
             }
 
                 }
             }
 
+    @staticmethod
+    def _remove_contexts():
+        for context in base.Context.list:
+            context._delete_context()
+        base.Context.list = []
+
     def test__change_node_names(self):
 
         ctx_attrs = {
     def test__change_node_names(self):
 
         ctx_attrs = {
@@ -313,6 +405,7 @@ class TaskParserTestCase(unittest.TestCase):
             }
 
         my_context = dummy.DummyContext()
             }
 
         my_context = dummy.DummyContext()
+        self.addCleanup(self._remove_contexts)
         my_context.init(ctx_attrs)
 
         expected_scenario = {
         my_context.init(ctx_attrs)
 
         expected_scenario = {
@@ -355,6 +448,7 @@ class TaskParserTestCase(unittest.TestCase):
             }
 
         my_context = dummy.DummyContext()
             }
 
         my_context = dummy.DummyContext()
+        self.addCleanup(self._remove_contexts)
         my_context.init(ctx_attrs)
 
         scenario = copy.deepcopy(self.scenario)
         my_context.init(ctx_attrs)
 
         scenario = copy.deepcopy(self.scenario)
@@ -362,3 +456,144 @@ class TaskParserTestCase(unittest.TestCase):
 
         self.parser._change_node_names(scenario, [my_context])
         self.assertEqual(scenario, expected_scenario)
 
         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')])