Просмотр исходного кода

Add unit tests for the `service.py` module

Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
Mihaela Balutoiu 2 лет назад
Родитель
Сommit
bce6f2c3d1
1 измененных файлов с 281 добавлено и 0 удалено
  1. 281 0
      coriolis/tests/test_service.py

+ 281 - 0
coriolis/tests/test_service.py

@@ -0,0 +1,281 @@
+# Copyright 2023 Cloudbase Solutions Srl
+# All Rights Reserved.
+
+import logging
+import os
+from unittest import mock
+
+import ddt
+
+from coriolis import service
+from coriolis.tests import test_base
+
+
+@ddt.ddt
+class ServiceTestCase(test_base.CoriolisBaseTestCase):
+    """Test suite for the Coriolis Service class."""
+
+    @ddt.data(
+        (['--worker-process-count', '5'], 5, [], False),
+        (['--worker-process-count', '10'], 10, [], False),
+        (['--worker-process-count', '15'], 15, [], False),
+        (['--worker-process-count', '20'], 20, [], False),
+        ([], None, [], False),
+        (['--worker-process-count', '5', '--unknown-arg'], 5,
+         ['--unknown-arg'], False),
+        (['--worker-process-count', '-5'], None, None, True),
+        (['--worker-process-count', '0'], None, None, True),
+        (['--worker-process-count', 'not-a-number'], None, None, True)
+    )
+    @ddt.unpack
+    def test_get_worker_count_from_args(self, input_args, expected_count,
+                                        expected_unknown_args,
+                                        expect_exception):
+        if expect_exception:
+            self.assertRaises(SystemExit, service.get_worker_count_from_args,
+                              input_args)
+        else:
+            worker_count, unknown_args = service.get_worker_count_from_args(
+                input_args)
+            self.assertEqual(worker_count, expected_count)
+            self.assertEqual(unknown_args, expected_unknown_args)
+
+    @ddt.data(
+        ({}, False, False, [], logging.WARN),
+        ({'lock_path': ""}, False, False, [], logging.WARN),
+        ({'lock_path': "/path/to/locks"}, False, False, [], logging.WARN),
+        ({'lock_path': "/path/to/locks"}, True, False, [], logging.WARN),
+        ({'lock_path': "/path/to/locks"}, True, True, ['file1', 'file2'],
+         logging.WARN),
+        ({'lock_path': "/path/to/locks"}, True, True, [], logging.INFO),
+    )
+    @ddt.unpack
+    @mock.patch.object(os.path, 'exists')
+    @mock.patch.object(os.path, 'isdir')
+    @mock.patch.object(os, 'listdir')
+    def test_check_locks_dir_empty(self, oslo_concurrency, exists, isdir,
+                                   listdir, expected_log_level, mock_listdir,
+                                   mock_isdir, mock_exists):
+        mock_exists.return_value = exists
+        mock_isdir.return_value = isdir
+        mock_listdir.return_value = listdir
+        with mock.patch.object(service.CONF, 'oslo_concurrency',
+                               oslo_concurrency):
+            with self.assertLogs('coriolis.service', level=expected_log_level):
+                service.check_locks_dir_empty()
+
+
+class WSGIServiceTestCase(test_base.CoriolisBaseTestCase):
+    """Test suite for the Coriolis WSGIService class."""
+
+    @mock.patch.object(service.wsgi.Loader, 'load_app')
+    @mock.patch.object(service, 'rpc')
+    @mock.patch.object(service, 'CONF')
+    @mock.patch.object(service.wsgi, 'Server')
+    def test_init(self, mock_server, mock_conf, mock_rpc, mock_load_app):
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_conf.api_migration_listen_port = mock.sentinel.listen_port
+        mock_conf.api_migration_workers = mock.sentinel.workers
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_rpc.init.return_value = mock.sentinel.transport
+
+        wsgi_service = service.WSGIService(mock.sentinel.name, worker_count=10,
+                                           init_rpc=True)
+
+        mock_rpc.init.assert_called_once_with()
+        mock_load_app.assert_called_once_with(mock.sentinel.name)
+        mock_server.assert_called_once_with(
+            mock_conf,
+            mock.sentinel.name,
+            mock_load_app.return_value,
+            host=mock_conf.api_migration_listen,
+            port=mock_conf.api_migration_listen_port)
+        self.assertEqual(wsgi_service._host, mock_conf.api_migration_listen)
+        self.assertEqual(wsgi_service._port,
+                         mock_conf.api_migration_listen_port)
+        self.assertEqual(wsgi_service._workers, 10)
+        self.assertEqual(wsgi_service._app, mock_load_app.return_value)
+        self.assertEqual(wsgi_service._server, mock_server.return_value)
+
+    @mock.patch('platform.system')
+    @mock.patch('oslo_service.wsgi.Server')
+    @mock.patch('oslo_service.wsgi.Loader.load_app')
+    @mock.patch('coriolis.rpc.messaging.get_transport')
+    @mock.patch.object(service, 'CONF')
+    def test_init_windows(self, mock_conf, mock_get_transport, mock_load_app,
+                          mock_server, mock_system):
+        mock_system.return_value = "Windows"
+        mock_conf.api_migration_workers = None
+        mock_load_app.return_value = mock.MagicMock()
+        mock_server.return_value = mock.MagicMock()
+        mock_get_transport.return_value = mock.MagicMock()
+
+        result = service.WSGIService('test_service', None, True)
+
+        self.assertEqual(result._workers, 1)
+
+    @mock.patch('platform.system')
+    @mock.patch('oslo_service.wsgi.Server')
+    @mock.patch('oslo_service.wsgi.Loader.load_app')
+    @mock.patch('oslo_concurrency.processutils.get_worker_count')
+    @mock.patch('coriolis.rpc.messaging.get_transport')
+    @mock.patch.object(service, 'CONF')
+    def test_init_sets_workers_based_on_system_on_non_windows(
+            self, mock_conf, mock_get_transport, mock_get_worker_count,
+            mock_load_app, mock_server, mock_system):
+        mock_system.return_value = "Linux"
+        mock_conf.api_migration_workers = None
+        mock_load_app.return_value = mock.MagicMock()
+        mock_server.return_value = mock.MagicMock()
+        mock_get_transport.return_value = mock.MagicMock()
+
+        result = service.WSGIService('test_service', None, True)
+
+        self.assertEqual(result._workers, mock_get_worker_count.return_value)
+
+    @mock.patch.object(service, 'CONF')
+    @mock.patch('oslo_service.wsgi.Loader.load_app')
+    @mock.patch('coriolis.rpc.messaging.get_transport')
+    @mock.patch('eventlet.listen')
+    def test_service_methods(self, mock_listen, mock_get_transport,
+                             mock_load_app, mock_conf):
+        mock_conf.api_migration_workers = 10
+        mock_load_app.return_value = mock.MagicMock()
+        mock_get_transport.return_value = mock.MagicMock()
+        mock_socket = mock.MagicMock()
+        mock_socket.getsockname.return_value = ('localhost', 8080)
+        mock_listen.return_value = mock_socket
+
+        result = service.WSGIService('test_service', None, True)
+
+        result._server = mock.MagicMock()
+
+        self.assertEqual(result.get_workers_count(),
+                         mock_conf.api_migration_workers)
+
+        result.start()
+        result._server.start.assert_called_once()
+
+        result.stop()
+        result._server.stop.assert_called_once()
+
+        result.wait()
+        result._server.wait.assert_called_once()
+
+        result.reset()
+        result._server.reset.assert_called_once()
+
+
+class MessagingServiceTestCase(test_base.CoriolisBaseTestCase):
+    """Test suite for the Coriolis MessagingService class."""
+
+    @mock.patch.object(service, 'rpc')
+    @mock.patch.object(service, 'CONF')
+    @mock.patch.object(service.messaging, 'Target')
+    @mock.patch.object(service.utils, 'get_hostname')
+    def test_init(self, mock_get_hostname, mock_target, mock_conf, mock_rpc):
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_conf.api_migration_listen_port = mock.sentinel.listen_port
+        mock_conf.api_migration_workers = mock.sentinel.workers
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_rpc.init.return_value = mock.sentinel.transport
+        mock_get_hostname.return_value = mock.sentinel.hostname
+
+        messaging_service = service.MessagingService(
+            mock.sentinel.topic, mock.sentinel.endpoints,
+            mock.sentinel.version, worker_count=10, init_rpc=True)
+
+        mock_rpc.init.assert_called_once_with()
+        mock_target.assert_called_once_with(
+            topic=mock.sentinel.topic,
+            server=mock.sentinel.hostname,
+            version=mock.sentinel.version)
+        mock_rpc.get_server.assert_called_once_with(
+            mock_target.return_value, mock.sentinel.endpoints)
+        self.assertEqual(messaging_service._workers, 10)
+        self.assertEqual(messaging_service._server,
+                         mock_rpc.get_server.return_value)
+
+    @mock.patch('platform.system')
+    @mock.patch.object(service, 'rpc')
+    @mock.patch.object(service, 'CONF')
+    @mock.patch.object(service.messaging, 'Target')
+    @mock.patch.object(service.utils, 'get_hostname')
+    def test_init_windows(self, mock_get_hostname, mock_target, mock_conf,
+                          mock_rpc, mock_system):
+        mock_system.return_value = "Windows"
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_conf.api_migration_listen_port = mock.sentinel.listen_port
+        mock_conf.api_migration_workers = mock.sentinel.workers
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_rpc.init.return_value = mock.sentinel.transport
+        mock_get_hostname.return_value = mock.sentinel.hostname
+
+        messaging_service = service.MessagingService(
+            mock.sentinel.topic, mock.sentinel.endpoints,
+            mock.sentinel.version, worker_count=10, init_rpc=True)
+
+        mock_rpc.init.assert_called_once_with()
+        mock_target.assert_called_once_with(
+            topic=mock.sentinel.topic,
+            server=mock.sentinel.hostname,
+            version=mock.sentinel.version)
+        mock_rpc.get_server.assert_called_once_with(
+            mock_target.return_value, mock.sentinel.endpoints)
+        self.assertEqual(messaging_service._workers, 1)
+        self.assertEqual(messaging_service._server,
+                         mock_rpc.get_server.return_value)
+
+    @mock.patch.object(service, 'rpc')
+    @mock.patch.object(service, 'CONF')
+    @mock.patch.object(service.utils, 'get_hostname')
+    @mock.patch.object(service.processutils, 'get_worker_count')
+    def test_init_with_none_worker_count(self, mock_get_worker_count,
+                                         mock_get_hostname,
+                                         mock_conf, mock_rpc):
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_conf.api_migration_listen_port = mock.sentinel.listen_port
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_rpc.init.return_value = mock.sentinel.transport
+        mock_get_hostname.return_value = mock.sentinel.hostname
+
+        result = service.MessagingService(
+            mock.sentinel.topic, mock.sentinel.endpoints,
+            mock.sentinel.version, worker_count=None, init_rpc=True)
+
+        self.assertEqual(result._workers, mock_get_worker_count.return_value)
+
+    @mock.patch.object(service, 'rpc')
+    @mock.patch.object(service, 'CONF')
+    @mock.patch.object(service.utils, 'get_hostname')
+    @mock.patch.object(service.processutils, 'get_worker_count')
+    def test_service_methods(self, mock_get_worker_count, mock_get_hostname,
+                             mock_conf, mock_rpc):
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_conf.api_migration_listen_port = mock.sentinel.listen_port
+        mock_conf.api_migration_workers = mock.sentinel.worker_count
+        mock_conf.api_migration_listen = mock.sentinel.listen
+        mock_rpc.init.return_value = mock.sentinel.transport
+        mock_get_hostname.return_value = mock.sentinel.hostname
+        mock_get_worker_count.return_value = mock.sentinel.worker_count
+
+        mock_server = mock.MagicMock()
+        mock_rpc.get_server.return_value = mock_server
+
+        result = service.MessagingService(
+            mock.sentinel.topic, mock.sentinel.endpoints,
+            mock.sentinel.version, worker_count=None, init_rpc=True)
+
+        self.assertEqual(result.get_workers_count(),
+                         mock.sentinel.worker_count)
+
+        result.start()
+        mock_server.start.assert_called_once()
+
+        result.stop()
+        mock_server.stop.assert_called_once()
+
+        result.wait()
+
+        result.reset()
+        mock_server.reset.assert_called_once()