From 6d361c6804b85b870add58b5b4a6c7df8e9476d4 Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Tue, 3 Jan 2017 08:30:51 +0100 Subject: Patch logging.FileHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It avoids creating a dummy functest.log for unit testing. Change-Id: Ib163d5d58284822b1904444fb60b08e92ee0ab9b Signed-off-by: Cédric Ollivier --- functest/tests/unit/cli/commands/test_cli_env.py | 1 + functest/tests/unit/core/test_testcase_base.py | 1 + functest/tests/unit/odl/test_odl.py | 1 + functest/tests/unit/utils/test_functest_utils.py | 1 + 4 files changed, 4 insertions(+) (limited to 'functest/tests') diff --git a/functest/tests/unit/cli/commands/test_cli_env.py b/functest/tests/unit/cli/commands/test_cli_env.py index 4b6ea57a..f70761dc 100644 --- a/functest/tests/unit/cli/commands/test_cli_env.py +++ b/functest/tests/unit/cli/commands/test_cli_env.py @@ -11,6 +11,7 @@ import unittest from git.exc import NoSuchPathError import mock +mock.patch('logging.FileHandler').start() # noqa from functest.cli.commands import cli_env from functest.utils.constants import CONST from functest.tests.unit import test_utils diff --git a/functest/tests/unit/core/test_testcase_base.py b/functest/tests/unit/core/test_testcase_base.py index b7c81d87..b6efa40d 100644 --- a/functest/tests/unit/core/test_testcase_base.py +++ b/functest/tests/unit/core/test_testcase_base.py @@ -11,6 +11,7 @@ import logging import mock import unittest +mock.patch('logging.FileHandler').start() # noqa from functest.core import testcase_base diff --git a/functest/tests/unit/odl/test_odl.py b/functest/tests/unit/odl/test_odl.py index d8c7f84e..4430c3b8 100644 --- a/functest/tests/unit/odl/test_odl.py +++ b/functest/tests/unit/odl/test_odl.py @@ -17,6 +17,7 @@ from keystoneauth1.exceptions import auth_plugins from robot.errors import RobotError from robot.result import testcase +mock.patch('logging.FileHandler').start() # noqa from functest.core import testcase_base from functest.opnfv_tests.sdn.odl import odl diff --git a/functest/tests/unit/utils/test_functest_utils.py b/functest/tests/unit/utils/test_functest_utils.py index ce9086a7..c4b56660 100644 --- a/functest/tests/unit/utils/test_functest_utils.py +++ b/functest/tests/unit/utils/test_functest_utils.py @@ -18,6 +18,7 @@ import mock import requests from functest.tests.unit import test_utils +mock.patch('logging.FileHandler').start() # noqa from functest.utils import functest_utils -- cgit 1.2.3-korg From 1f59d1e080531d333fd0eb4fea0a4714c709da07 Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Tue, 3 Jan 2017 10:38:53 +0100 Subject: Use mock_open() to prevent stdout.txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /home/opnfv is no longer required. Change-Id: Iefb8faf3a7d548f3ae7d4076005d7b0bb93e63e1 Signed-off-by: Cédric Ollivier --- functest/tests/unit/odl/test_odl.py | 12 ++++++++++++ run_unit_tests.sh | 7 ------- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'functest/tests') diff --git a/functest/tests/unit/odl/test_odl.py b/functest/tests/unit/odl/test_odl.py index 4430c3b8..8d184203 100644 --- a/functest/tests/unit/odl/test_odl.py +++ b/functest/tests/unit/odl/test_odl.py @@ -195,6 +195,8 @@ class ODLTesting(unittest.TestCase): def test_main_robot_run_failed(self, *args): with mock.patch.object(self.test, 'set_robotframework_vars', return_value=True), \ + mock.patch.object(odl, 'open', mock.mock_open(), + create=True), \ self.assertRaises(RobotError): self._test_main(testcase_base.TestcaseBase.EX_RUN_ERROR, *args) @@ -203,6 +205,8 @@ class ODLTesting(unittest.TestCase): def test_main_parse_results_failed(self, *args): with mock.patch.object(self.test, 'set_robotframework_vars', return_value=True), \ + mock.patch.object(odl, 'open', mock.mock_open(), + create=True), \ mock.patch.object(self.test, 'parse_results', side_effect=RobotError): self._test_main(testcase_base.TestcaseBase.EX_RUN_ERROR, *args) @@ -223,6 +227,8 @@ class ODLTesting(unittest.TestCase): def test_main(self, *args): with mock.patch.object(self.test, 'set_robotframework_vars', return_value=True), \ + mock.patch.object(odl, 'open', mock.mock_open(), + create=True), \ mock.patch.object(self.test, 'parse_results'): self._test_main(testcase_base.TestcaseBase.EX_OK, *args) @@ -232,6 +238,8 @@ class ODLTesting(unittest.TestCase): def test_main_makedirs_oserror17(self, *args): with mock.patch.object(self.test, 'set_robotframework_vars', return_value=True), \ + mock.patch.object(odl, 'open', mock.mock_open(), + create=True), \ mock.patch.object(self.test, 'parse_results'): self._test_main(testcase_base.TestcaseBase.EX_OK, *args) @@ -241,6 +249,8 @@ class ODLTesting(unittest.TestCase): def test_main_testcases_in_failure(self, *args): with mock.patch.object(self.test, 'set_robotframework_vars', return_value=True), \ + mock.patch.object(odl, 'open', mock.mock_open(), + create=True), \ mock.patch.object(self.test, 'parse_results'): self._test_main(testcase_base.TestcaseBase.EX_OK, *args) @@ -250,6 +260,8 @@ class ODLTesting(unittest.TestCase): def test_main_remove_oserror(self, *args): with mock.patch.object(self.test, 'set_robotframework_vars', return_value=True), \ + mock.patch.object(odl, 'open', mock.mock_open(), + create=True), \ mock.patch.object(self.test, 'parse_results'): self._test_main(testcase_base.TestcaseBase.EX_OK, *args) diff --git a/run_unit_tests.sh b/run_unit_tests.sh index edce03c1..c18f3cab 100755 --- a/run_unit_tests.sh +++ b/run_unit_tests.sh @@ -18,13 +18,6 @@ function clean_results_dir { # clean it anyway clean_results_dir -# TODO clean that... -# Create log dir if needed -# log shall be disabled during unit tests -sudo mkdir -p /home/opnfv/functest/results/odl -sudo touch /home/opnfv/functest/results/odl/stdout.txt -sudo chmod -Rf a+rw /home/opnfv - # Either Workspace is set (CI) if [ -z $WORKSPACE ] then -- cgit 1.2.3-korg From a7af7049fa6ee0b5d4dadb026c31e3587d8f3b4c Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Tue, 3 Jan 2017 17:36:43 +0100 Subject: Fully cover set_robotframework_vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit re.sub() is now tested. Change-Id: I83cf69b66cd1407f5e4439d8c545338c5fb0bde7 Signed-off-by: Cédric Ollivier --- functest/tests/unit/odl/test_odl.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'functest/tests') diff --git a/functest/tests/unit/odl/test_odl.py b/functest/tests/unit/odl/test_odl.py index 8d184203..8dcc9bd9 100644 --- a/functest/tests/unit/odl/test_odl.py +++ b/functest/tests/unit/odl/test_odl.py @@ -11,6 +11,7 @@ import errno import logging import mock import os +import StringIO import unittest from keystoneauth1.exceptions import auth_plugins @@ -78,9 +79,39 @@ class ODLTesting(unittest.TestCase): self.assertFalse(self.test.set_robotframework_vars()) @mock.patch('fileinput.input', return_value=[]) - def test_set_robotframework_vars(self, args): + def test_set_robotframework_vars_empty(self, args): self.assertTrue(self.test.set_robotframework_vars()) + @mock.patch('sys.stdout', new_callable=StringIO.StringIO) + def _test_set_robotframework_vars(self, msg1, msg2, *args): + line = mock.MagicMock() + line.__iter__.return_value = [msg1] + with mock.patch('fileinput.input', return_value=line) as mock_method: + self.assertTrue(self.test.set_robotframework_vars()) + mock_method.assert_called_once_with( + os.path.join(odl.ODLTests.odl_test_repo, + 'csit/variables/Variables.py'), inplace=True) + self.assertEqual(args[0].getvalue(), "{}\n".format(msg2)) + + def test_set_robotframework_vars_auth_default(self): + self._test_set_robotframework_vars("AUTH = []", + "AUTH = [u'admin', u'admin']") + + def test_set_robotframework_vars_auth1(self): + self._test_set_robotframework_vars("AUTH1 = []", "AUTH1 = []") + + @mock.patch('sys.stdout', new_callable=StringIO.StringIO) + def test_set_robotframework_vars_auth_foo(self, *args): + line = mock.MagicMock() + line.__iter__.return_value = ["AUTH = []"] + with mock.patch('fileinput.input', return_value=line) as mock_method: + self.assertTrue(self.test.set_robotframework_vars('foo', 'bar')) + mock_method.assert_called_once_with( + os.path.join(odl.ODLTests.odl_test_repo, + 'csit/variables/Variables.py'), inplace=True) + self.assertEqual(args[0].getvalue(), + "AUTH = [u'{}', u'{}']\n".format('foo', 'bar')) + @classmethod def _fake_url_for(cls, service_type='identity', **kwargs): if service_type == 'identity': -- cgit 1.2.3-korg From b30ad39874519322b5b866d2a5fe6a43c6efd6a4 Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Wed, 4 Jan 2017 16:32:08 +0100 Subject: Create ODLParser to parse sys.argv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It helps covering lines about args parsing without calling main. It also excludes 'if __name__ == .__main__.:' from coverage. The related unit tests are added too. Change-Id: I8e001a9d35081000977e0e546ae505f7cf2870e6 Signed-off-by: Cédric Ollivier --- .coveragerc | 3 ++ functest/opnfv_tests/sdn/odl/odl.py | 80 ++++++++++++++++++++---------------- functest/tests/unit/odl/test_odl.py | 82 +++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 36 deletions(-) create mode 100644 .coveragerc (limited to 'functest/tests') diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..fe258c6c --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +[report] +exclude_lines = + if __name__ == .__main__.: diff --git a/functest/opnfv_tests/sdn/odl/odl.py b/functest/opnfv_tests/sdn/odl/odl.py index 0905e55c..80827e42 100755 --- a/functest/opnfv_tests/sdn/odl/odl.py +++ b/functest/opnfv_tests/sdn/odl/odl.py @@ -180,44 +180,52 @@ class ODLTests(testcase_base.TestcaseBase): return self.main(**kwargs) +class ODLParser(): + + def __init__(self): + self.parser = argparse.ArgumentParser() + self.parser.add_argument( + '-k', '--keystoneip', help='Keystone IP', + default='127.0.0.1') + self.parser.add_argument( + '-n', '--neutronip', help='Neutron IP', + default='127.0.0.1') + self.parser.add_argument( + '-a', '--osusername', help='Username for OpenStack', + default='admin') + self.parser.add_argument( + '-b', '--ostenantname', help='Tenantname for OpenStack', + default='admin') + self.parser.add_argument( + '-c', '--ospassword', help='Password for OpenStack', + default='admin') + self.parser.add_argument( + '-o', '--odlip', help='OpenDaylight IP', + default='127.0.0.1') + self.parser.add_argument( + '-w', '--odlwebport', help='OpenDaylight Web Portal Port', + default='8080') + self.parser.add_argument( + '-r', '--odlrestconfport', help='OpenDaylight RESTConf Port', + default='8181') + self.parser.add_argument( + '-d', '--odlusername', help='Username for ODL', + default='admin') + self.parser.add_argument( + '-e', '--odlpassword', help='Password for ODL', + default='admin') + self.parser.add_argument( + '-p', '--pushtodb', help='Push results to DB', + action='store_true') + + def parse_args(self, argv=[]): + return vars(self.parser.parse_args(argv)) + + if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('-k', '--keystoneip', - help='Keystone IP', - default='127.0.0.1') - parser.add_argument('-n', '--neutronip', - help='Neutron IP', - default='127.0.0.1') - parser.add_argument('-a', '--osusername', - help='Username for OpenStack', - default='admin') - parser.add_argument('-b', '--ostenantname', - help='Tenantname for OpenStack', - default='admin') - parser.add_argument('-c', '--ospassword', - help='Password for OpenStack', - default='admin') - parser.add_argument('-o', '--odlip', - help='OpenDaylight IP', - default='127.0.0.1') - parser.add_argument('-w', '--odlwebport', - help='OpenDaylight Web Portal Port', - default='8080') - parser.add_argument('-r', '--odlrestconfport', - help='OpenDaylight RESTConf Port', - default='8181') - parser.add_argument('-d', '--odlusername', - help='Username for ODL', - default='admin') - parser.add_argument('-e', '--odlpassword', - help='Password for ODL', - default='admin') - parser.add_argument('-p', '--pushtodb', - help='Push results to DB', - action='store_true') - - args = vars(parser.parse_args()) odl = ODLTests() + parser = ODLParser() + args = parser.parse_args(sys.argv[1:]) try: result = odl.main(**args) if result != testcase_base.TestcaseBase.EX_OK: diff --git a/functest/tests/unit/odl/test_odl.py b/functest/tests/unit/odl/test_odl.py index 8dcc9bd9..3878337b 100644 --- a/functest/tests/unit/odl/test_odl.py +++ b/functest/tests/unit/odl/test_odl.py @@ -46,6 +46,17 @@ class ODLTesting(unittest.TestCase): os.environ["OS_PASSWORD"] = self._os_password os.environ["OS_TENANT_NAME"] = self._os_tenantname self.test = odl.ODLTests() + self.defaultargs = {'odlusername': self._odl_username, + 'odlpassword': self._odl_password, + 'keystoneip': self._keystone_ip, + 'neutronip': self._keystone_ip, + 'osusername': self._os_username, + 'ostenantname': self._os_tenantname, + 'ospassword': self._os_password, + 'odlip': self._keystone_ip, + 'odlwebport': self._odl_webport, + 'odlrestconfport': self._odl_restconfport, + 'pushtodb': False} def test_empty_visitor(self): visitor = odl.ODLResultVisitor() @@ -397,6 +408,77 @@ class ODLTesting(unittest.TestCase): self._test_run(testcase_base.TestcaseBase.EX_OK, odlip=self._neutron_ip, odlwebport='8181') + def test_argparser_default(self): + parser = odl.ODLParser() + self.assertEqual(parser.parse_args(), self.defaultargs) + + def test_argparser_basic(self): + self.defaultargs['neutronip'] = self._neutron_ip + self.defaultargs['odlip'] = self._sdn_controller_ip + parser = odl.ODLParser() + self.assertEqual(parser.parse_args( + ["--neutronip={}".format(self._neutron_ip), + "--odlip={}".format(self._sdn_controller_ip) + ]), self.defaultargs) + + @mock.patch('sys.stderr', new_callable=StringIO.StringIO) + def test_argparser_fail(self, *args): + self.defaultargs['foo'] = 'bar' + parser = odl.ODLParser() + with self.assertRaises(SystemExit): + parser.parse_args(["--foo=bar"]) + + def _test_argparser(self, arg, value): + self.defaultargs[arg] = value + parser = odl.ODLParser() + self.assertEqual(parser.parse_args(["--{}={}".format(arg, value)]), + self.defaultargs) + + def test_argparser_odlusername(self): + self._test_argparser('odlusername', 'foo') + + def test_argparser_odlpassword(self): + self._test_argparser('odlpassword', 'foo') + + def test_argparser_keystoneip(self): + self._test_argparser('keystoneip', '127.0.0.4') + + def test_argparser_neutronip(self): + self._test_argparser('neutronip', '127.0.0.4') + + def test_argparser_osusername(self): + self._test_argparser('osusername', 'foo') + + def test_argparser_ostenantname(self): + self._test_argparser('ostenantname', 'foo') + + def test_argparser_ospassword(self): + self._test_argparser('ospassword', 'foo') + + def test_argparser_odlip(self): + self._test_argparser('odlip', '127.0.0.4') + + def test_argparser_odlwebport(self): + self._test_argparser('odlwebport', '80') + + def test_argparser_odlrestconfport(self): + self._test_argparser('odlrestconfport', '80') + + def test_argparser_pushtodb(self): + self.defaultargs['pushtodb'] = True + parser = odl.ODLParser() + self.assertEqual(parser.parse_args(["--{}".format('pushtodb')]), + self.defaultargs) + + def test_argparser_multiple_args(self): + self.defaultargs['neutronip'] = self._neutron_ip + self.defaultargs['odlip'] = self._sdn_controller_ip + parser = odl.ODLParser() + self.assertEqual(parser.parse_args( + ["--neutronip={}".format(self._neutron_ip), + "--odlip={}".format(self._sdn_controller_ip) + ]), self.defaultargs) + if __name__ == "__main__": unittest.main(verbosity=2) -- cgit 1.2.3-korg From b46115a43bcbe7214178f00cc97a8e5de018ee3f Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Thu, 5 Jan 2017 09:00:04 +0100 Subject: Switch to assert_any_call in test_show_credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous test can be false if users set OS_ env vars. Change-Id: If517582d77aa1373bf253d7e23731e2e896d26ac Signed-off-by: Cédric Ollivier --- functest/tests/unit/cli/commands/test_cli_os.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'functest/tests') diff --git a/functest/tests/unit/cli/commands/test_cli_os.py b/functest/tests/unit/cli/commands/test_cli_os.py index 9e704806..f0e58c67 100644 --- a/functest/tests/unit/cli/commands/test_cli_os.py +++ b/functest/tests/unit/cli/commands/test_cli_os.py @@ -231,7 +231,7 @@ class CliOpenStackTesting(unittest.TestCase): value = 'OS_VALUE' with mock.patch.dict(os.environ, {key: value}): self.cli_os.show_credentials() - mock_click_echo.assert_called_once_with("{}={}".format(key, value)) + mock_click_echo.assert_any_call("{}={}".format(key, value)) if __name__ == "__main__": -- cgit 1.2.3-korg From 1406a4e103188cdb59bedfacc0d1a1ce3e15cb03 Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Thu, 5 Jan 2017 11:46:46 +0100 Subject: Cover ODLTests.parse_results() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ODL testcase is now fully covered by unit tests. Change-Id: I856a40138739b148babcfa96e82da05bb83e63e1 Signed-off-by: Cédric Ollivier --- functest/opnfv_tests/sdn/odl/odl.py | 6 +++--- functest/tests/unit/odl/test_odl.py | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'functest/tests') diff --git a/functest/opnfv_tests/sdn/odl/odl.py b/functest/opnfv_tests/sdn/odl/odl.py index 80827e42..45b313d5 100755 --- a/functest/opnfv_tests/sdn/odl/odl.py +++ b/functest/opnfv_tests/sdn/odl/odl.py @@ -15,7 +15,7 @@ import re import sys import urlparse -from robot.api import ExecutionResult, ResultVisitor +import robot.api from robot.errors import RobotError import robot.run from robot.utils.robottime import timestamp_to_secs @@ -25,7 +25,7 @@ import functest.utils.functest_logger as ft_logger import functest.utils.openstack_utils as op_utils -class ODLResultVisitor(ResultVisitor): +class ODLResultVisitor(robot.api.ResultVisitor): def __init__(self): self._data = [] @@ -79,7 +79,7 @@ class ODLTests(testcase_base.TestcaseBase): def parse_results(self): xml_file = os.path.join(self.res_dir, 'output.xml') - result = ExecutionResult(xml_file) + result = robot.api.ExecutionResult(xml_file) visitor = ODLResultVisitor() result.visit(visitor) self.criteria = result.suite.status diff --git a/functest/tests/unit/odl/test_odl.py b/functest/tests/unit/odl/test_odl.py index 3878337b..d45d5628 100644 --- a/functest/tests/unit/odl/test_odl.py +++ b/functest/tests/unit/odl/test_odl.py @@ -15,8 +15,9 @@ import StringIO import unittest from keystoneauth1.exceptions import auth_plugins -from robot.errors import RobotError +from robot.errors import DataError, RobotError from robot.result import testcase +from robot.utils.robottime import timestamp_to_secs mock.patch('logging.FileHandler').start() # noqa from functest.core import testcase_base @@ -85,6 +86,27 @@ class ODLTesting(unittest.TestCase): visitor.visit_test(test) self.assertEqual(visitor.get_data(), [data]) + @mock.patch('robot.api.ExecutionResult', side_effect=DataError) + def test_parse_results_raises_exceptions(self, *args): + with self.assertRaises(DataError): + self.test.parse_results() + + def test_parse_results(self, *args): + config = {'name': 'dummy', 'starttime': '20161216 16:00:00.000', + 'endtime': '20161216 16:00:01.000', 'status': 'PASS'} + suite = mock.Mock() + suite.configure_mock(**config) + with mock.patch('robot.api.ExecutionResult', + return_value=mock.Mock(suite=suite)): + self.test.parse_results() + self.assertEqual(self.test.criteria, config['status']) + self.assertEqual(self.test.start_time, + timestamp_to_secs(config['starttime'])) + self.assertEqual(self.test.stop_time, + timestamp_to_secs(config['endtime'])) + self.assertEqual(self.test.details, + {'description': config['name'], 'tests': []}) + @mock.patch('fileinput.input', side_effect=Exception()) def test_set_robotframework_vars_failed(self, *args): self.assertFalse(self.test.set_robotframework_vars()) -- cgit 1.2.3-korg