[virt-tools-list] [virt-bootstrap] [PATCH v3 07/12] tests: Add unit tests for 'virt_bootstrap' module

Radostin Stoyanov rstoyanov1 at gmail.com
Thu Jul 20 11:29:42 UTC 2017


---
 tests/__init__.py            |  42 +++++++
 tests/test_virt_bootstrap.py | 287 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 329 insertions(+)
 create mode 100644 tests/__init__.py
 create mode 100644 tests/test_virt_bootstrap.py

diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..2d3edce
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,42 @@
+"""
+
+Test suite for virt-bootstrap
+
+ Authors:
+    Cedric Bosdonnat <cbosdonnat at suse.com>
+    Radostin Stoyanov <rstoyanov1 at gmail.com>
+
+ Copyright (C) 2017 Radostin Stoyanov
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import sys
+import unittest
+
+try:
+    import mock
+except ImportError:
+    import unittest.mock as mock
+
+sys.path += '../src'  # noqa: E402
+
+# pylint: disable=import-error
+from virtBootstrap import virt_bootstrap
+from virtBootstrap import sources
+from virtBootstrap import progress
+from virtBootstrap import utils
+
+__all__ = ['unittest', 'mock',
+           'virt_bootstrap', 'sources', 'progress', 'utils']
diff --git a/tests/test_virt_bootstrap.py b/tests/test_virt_bootstrap.py
new file mode 100644
index 0000000..4d66211
--- /dev/null
+++ b/tests/test_virt_bootstrap.py
@@ -0,0 +1,287 @@
+# Authors:
+#   Cedric Bosdonnat <cbosdonnat at suse.com>
+#   Radostin Stoyanov <rstoyanov1 at gmail.com>
+#
+# Copyright (C) 2017 SUSE, Inc.
+# Copyright (C) 2017 Radostin Stoyanov
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+"""
+Unit tests for functions defined in virtBootstrap.virt-bootstrap
+"""
+
+from tests import unittest
+from tests import mock
+from tests import virt_bootstrap
+from tests import sources
+
+
+# pylint: disable=invalid-name
+class TestVirtBootstrap(unittest.TestCase):
+    """
+    Test cases for virt_bootstrap module
+    """
+
+    ###################################
+    # Tests for: get_source(source_type)
+    ###################################
+    def test_get_invaid_source_type_should_fail(self):
+        """
+        Ensures that get_source() throws an Exception when invalid source
+        name was specified.
+        """
+        with self.assertRaises(Exception) as source:
+            virt_bootstrap.get_source('fake')
+        self.assertIn('fake', str(source.exception))
+
+    def test_get_docker_source(self):
+        """
+        Ensures that get_source() returns DockerSource when source name
+        "docker" is requested.
+        """
+        self.assertIs(virt_bootstrap.get_source('docker'),
+                      sources.DockerSource)
+
+    def test_get_file_source(self):
+        """
+        Ensures that get_source() returns FileSource when source name
+        "file" is requested.
+        """
+        self.assertIs(virt_bootstrap.get_source('file'),
+                      sources.FileSource)
+
+    ###################################
+    # Tests for: map_id()
+    ###################################
+    @mock.patch('os.path.realpath')
+    def test_map_id(self, m_realpath):
+        """
+        Ensures that the UID/GID mapping applies to all files
+        and directories in root file system.
+        """
+        root_path = '/root'
+        files = ['foo1', 'foo2']
+        uid = gid = {}
+        uid['mapped'] = 1000
+        gid['mapped'] = 1001
+        uid['user'] = 10
+        gid['user'] = 0
+        uid['file'] = 10
+        gid['file'] = 100
+        for i in [uid, gid]:
+            i['expected'] = i['mapped'] + i['file'] - i['user']
+
+        files_path = ["%s/%s" % (root_path, filename) for filename in files]
+        expected_calls = [mock.call(path, uid['expected'], gid['expected'])
+                          for path in [root_path] + files_path]
+
+        m_realpath.return_value = root_path
+        with mock.patch.multiple('os',
+                                 geteuid=mock.DEFAULT,
+                                 getegid=mock.DEFAULT,
+                                 lchown=mock.DEFAULT,
+                                 lstat=mock.DEFAULT,
+                                 walk=mock.DEFAULT) as mocked:
+            mocked['geteuid'].return_value = uid['user']
+            mocked['getegid'].return_value = gid['user']
+            mocked['walk'].return_value = [(root_path, [], files)]
+            mocked['lstat']().st_uid = uid['file']
+            mocked['lstat']().st_gid = gid['file']
+
+            virt_bootstrap.map_id(root_path, uid['mapped'], gid['mapped'])
+
+        mocked['lchown'].assert_has_calls(expected_calls)
+
+    ###################################
+    # Tests for: bootstrap()
+    ###################################
+    def test_bootsrap_creates_directory_if_does_not_exist(self):
+        """
+        Ensures that bootstrap() creates destination directory if
+        it does not exists.
+        """
+        src, dest = 'foo', 'bar'
+        with mock.patch.multiple(virt_bootstrap,
+                                 get_source=mock.DEFAULT,
+                                 os=mock.DEFAULT) as mocked:
+            mocked['os'].path.exists.return_value = False
+            virt_bootstrap.bootstrap(src, dest)
+            mocked['os'].path.exists.assert_called_once_with(dest)
+            mocked['os'].makedirs.assert_called_once_with(dest)
+
+    def test_bootstrap_exit_if_dest_is_invalid(self):
+        """
+        Ensures that bootstrap() exits with code 1 when the destination
+        path exists but it is not directory.
+        """
+        src, dest = 'foo', 'bar'
+        with mock.patch.multiple(virt_bootstrap,
+                                 get_source=mock.DEFAULT,
+                                 os=mock.DEFAULT,
+                                 logger=mock.DEFAULT,
+                                 sys=mock.DEFAULT) as mocked:
+            mocked['os'].path.exists.return_value = True
+            mocked['os'].path.isdir.return_value = False
+            virt_bootstrap.bootstrap(src, dest)
+            mocked['os'].path.isdir.assert_called_once_with(dest)
+            mocked['sys'].exit.assert_called_once_with(1)
+
+    def test_bootsrap_exit_if_no_write_access_on_dest(self):
+        """
+        Ensures that bootstrap() exits with code 1 when the current user
+        has not write permissions on the destination folder.
+        """
+        src, dest = 'foo', 'bar'
+        with mock.patch.multiple(virt_bootstrap,
+                                 get_source=mock.DEFAULT,
+                                 os=mock.DEFAULT,
+                                 logger=mock.DEFAULT,
+                                 sys=mock.DEFAULT) as mocked:
+            mocked['os'].path.exists.return_value = True
+            mocked['os'].path.isdir.return_value = True
+            mocked['os'].access.return_value = False
+            virt_bootstrap.bootstrap(src, dest)
+            mocked['os'].access.assert_called_once_with(dest,
+                                                        mocked['os'].W_OK)
+            mocked['sys'].exit.assert_called_once_with(1)
+
+    def test_bootstrap_use_file_source_if_none_was_specified(self):
+        """
+        Ensures that bootstrap() calls get_source() with argument
+        'file' when source format is not specified.
+        """
+        src, dest = 'foo', 'bar'
+        with mock.patch.multiple(virt_bootstrap,
+                                 get_source=mock.DEFAULT,
+                                 os=mock.DEFAULT,
+                                 sys=mock.DEFAULT) as mocked:
+            virt_bootstrap.bootstrap(src, dest)
+            mocked['get_source'].assert_called_once_with('file')
+
+    def test_bootstrap_successful_call(self):
+        """
+        Ensures that bootstrap() creates source instance and calls the
+        unpack method with destination path as argument.
+        """
+        src, dest = 'foo', 'bar'
+        with mock.patch.multiple(virt_bootstrap,
+                                 get_source=mock.DEFAULT,
+                                 os=mock.DEFAULT,
+                                 sys=mock.DEFAULT) as mocked:
+            mocked['os'].path.exists.return_value = True
+            mocked['os'].path.isdir.return_value = True
+            mocked['os'].access.return_value = True
+            mocked_source = mock.Mock()
+            mocked_unpack = mock.Mock()
+            mocked_source.return_value.unpack = mocked_unpack
+            mocked['get_source'].return_value = mocked_source
+            virt_bootstrap.bootstrap(src, dest)
+            # sys.exit should not be called
+            mocked['sys'].exit.assert_not_called()
+            mocked_source.assert_called_once()
+            mocked_unpack.assert_called_once_with(dest)
+
+    def test_bootstrap_all_params_are_passed_to_source_instance(self):
+        """
+        Ensures that bootstrap() is passing all arguments to newly created
+        source instance.
+        """
+        params_list = ['dest', 'fmt', 'username', 'password', 'root_password',
+                       'not_secure', 'no_cache', 'progress_cb']
+        params = {param: param for param in params_list}
+
+        for kw_param in params_list:
+            params[kw_param] = kw_param
+
+        with mock.patch.multiple(virt_bootstrap,
+                                 get_source=mock.DEFAULT,
+                                 os=mock.DEFAULT,
+                                 urlparse=mock.DEFAULT,
+                                 progress=mock.DEFAULT,
+                                 utils=mock.DEFAULT,
+                                 sys=mock.DEFAULT) as mocked:
+            mocked['os'].path.exists.return_value = True
+            mocked['os'].path.isdir.return_value = True
+            mocked['os'].access.return_value = True
+
+            mocked['progress'].Progress.return_value = params['progress_cb']
+
+            mocked_source = mock.Mock()
+            mocked_unpack = mock.Mock()
+            mocked_source.return_value.unpack = mocked_unpack
+            mocked['get_source'].return_value = mocked_source
+
+            mocked_uri = mock.Mock()
+            mocked['urlparse'].return_value = mocked_uri
+            params['uri'] = mocked_uri
+
+            virt_bootstrap.bootstrap(**params)
+            # sys.exit should not be called
+            mocked['sys'].exit.assert_not_called()
+
+            mocked_source.assert_called_once()
+            mocked_unpack.assert_called_once_with(params['dest'])
+
+            called_with_args, called_with_kwargs = mocked_source.call_args
+            self.assertEqual(called_with_args, ())
+
+            del params['dest']
+            del params['root_password']
+            params['progress'] = params.pop('progress_cb')
+            for kwarg in params:
+                self.assertEqual(called_with_kwargs[kwarg], params[kwarg])
+
+    def test_if_bootstrap_calls_set_root_password(self):
+        """
+        Ensures that bootstrap() calls set_root_password() when the argument
+        root_password is specified.
+        """
+        src, dest, root_password = 'foo', 'bar', 'root_password'
+        with mock.patch.multiple(virt_bootstrap,
+                                 get_source=mock.DEFAULT,
+                                 os=mock.DEFAULT,
+                                 utils=mock.DEFAULT,
+                                 sys=mock.DEFAULT) as mocked:
+            mocked['os'].path.exists.return_value = True
+            mocked['os'].path.isdir.return_value = True
+            mocked['os'].access.return_value = True
+
+            virt_bootstrap.bootstrap(src, dest, root_password=root_password)
+            mocked['utils'].set_root_password.assert_called_once_with(
+                dest, root_password)
+
+    ###################################
+    # Tests for: set_logging_conf()
+    ###################################
+    def test_if_logging_level_format_handler_are_set(self):
+        """
+        Ensures that set_logging_conf() sets log level and adds new stream
+        handler with formatting.
+        """
+        with mock.patch('virtBootstrap.virt_bootstrap.logging') as m_logging:
+            mocked_stream_hdlr = mock.Mock()
+            m_logger = mock.Mock()
+            m_logging.getLogger.return_value = m_logger
+            m_logging.StreamHandler.return_value = mocked_stream_hdlr
+            virt_bootstrap.set_logging_conf()
+            m_logging.getLogger.assert_called_once_with('virtBootstrap')
+            mocked_stream_hdlr.setFormatter.assert_called_once()
+            m_logger.addHandler.assert_called_once_with(mocked_stream_hdlr)
+            m_logger.setLevel.assert_called_once()
+
+
+if __name__ == '__main__':
+    unittest.main(exit=False)
-- 
2.9.4




More information about the virt-tools-list mailing list