Files
storlets/tests/unit/agent/daemon_factory/test_server.py
Takashi Kajinami cfe221f529 Rename STORLETS_CONTAINER_DEVICE
This does not represent actual device, but the directory where relevant
data is stored.

Also rename the root directory in the container to avoid the term
"swift" within the container.

Change-Id: I128ac692ae33944ab95e251cc4cd545a3b8e6cd7
Signed-off-by: Takashi Kajinami <kajinamit@oss.nttdata.com>
2025-08-14 21:07:57 +09:00

704 lines
31 KiB
Python

# Copyright (c) 2015-2016 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from contextlib import contextmanager
import errno
import unittest
from unittest import mock
from storlets.sbus import command as sbus_cmd
from storlets.sbus.client import SBusResponse
from storlets.sbus.client.exceptions import SBusClientSendError
from storlets.agent.daemon_factory.server import SDaemonError, \
StorletDaemonFactory
from tests.unit import FakeLogger
from tests.unit.agent.common import test_server
class DummyDatagram(object):
def __init__(self, prms=None):
self.params = prms or {}
class TestStorletDaemonFactory(unittest.TestCase):
# Class paths used in mock.patch
base_path = 'storlets.agent.daemon_factory.server'
os_environ_path = base_path + '.os.environ'
os_path_isfile_path = base_path + '.os.path.isfile'
os_access_path = base_path + '.os.access'
os_kill_path = base_path + '.os.kill'
os_waitpid_path = base_path + '.os.waitpid'
subprocess_popen_path = base_path + '.subprocess.Popen'
time_sleep_path = base_path + '.time.sleep'
@contextmanager
def _mock_sbus_client(self, method):
sbusclient_path = self.base_path + '.SBusClient'
with mock.patch('.'.join([sbusclient_path, method])) as _method:
yield _method
def setUp(self):
self.logger = FakeLogger()
self.pipe_path = 'path/to/pipe'
self.container_id = 'contid'
self.dfactory = StorletDaemonFactory(self.pipe_path, self.logger,
self.container_id)
def test_get_jvm_args(self):
dummy_env = {'CLASSPATH': '/default/classpath',
'LD_LIBRARY_PATH': '/default/ld/library/path'}
with mock.patch(self.os_environ_path, dummy_env):
pargs, env = self.dfactory.get_jvm_args(
'java', 'path/to/storlet/a', 'Storlet-1.0.jar',
1, 'path/to/uds/a', 'DEBUG')
self.assertEqual(
['/usr/bin/java', 'org.openstack.storlet.daemon.SDaemon',
'Storlet-1.0.jar', 'path/to/uds/a', 'DEBUG', '1',
self.container_id],
pargs)
self.assertIn('CLASSPATH', env)
self.assertEqual(
['/default/classpath',
'/usr/local/lib/storlets/java/*',
'/usr/local/lib/storlets/java/',
'path/to/storlet/a'],
env['CLASSPATH'].split(':'))
self.assertIn('LD_LIBRARY_PATH', env)
self.assertEqual(
['/default/ld/library/path',
'/usr/local/lib/storlets',
'/usr/local/lib/storlets/java'],
env['LD_LIBRARY_PATH'].split(':'))
def test_get_python_args(self):
self._test_get_python_args(None, '3')
self._test_get_python_args('3.10', '3.10')
self._test_get_python_args('3', '3')
def _test_get_python_args(self, version, expected):
dummy_env = {'PYTHONPATH': '/default/pythonpath'}
with mock.patch(self.os_environ_path, dummy_env):
pargs, env = self.dfactory.get_python_args(
'python', 'path/to/storlet', 'test_storlet.TestStorlet',
1, 'path/to/uds', 'DEBUG', version)
self.assertEqual(
['/usr/bin/python%s' % expected,
'/usr/local/libexec/storlets/storlets-daemon',
'test_storlet.TestStorlet',
'path/to/uds', 'DEBUG', '1', self.container_id],
pargs)
self.assertEqual(
{'PYTHONPATH': '/default/pythonpath:'
'/var/lib/storlets/test_storlet.TestStorlet'},
env)
def test_spawn_subprocess(self):
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'path/to/uds/a'}
class FakePopenObject(object):
def __init__(self, pid):
self.pid = pid
self.stderr = mock.MagicMock()
self.stdout = mock.MagicMock()
with mock.patch(self.os_path_isfile_path) as isfile, \
mock.patch(self.os_access_path) as access, \
mock.patch(self.subprocess_popen_path) as popen, \
mock.patch(self.time_sleep_path), \
mock.patch(self.os_waitpid_path) as waitpid, \
self._mock_sbus_client('ping') as ping:
isfile.return_value = True
access.return_velue = True
popen.side_effect = [FakePopenObject(1000),
FakePopenObject(1001)]
waitpid.return_value = 0, 0
ping.return_value = SBusResponse(True, 'OK')
self.dfactory.spawn_subprocess(
['arg0', 'argv1', 'argv2'],
{'envk0': 'envv0'}, 'storleta')
self.assertEqual(('arg0',), isfile.call_args[0])
self.assertEqual((1000, 1), waitpid.call_args[0])
self.assertEqual({'storleta': 1000},
self.dfactory.storlet_name_to_pid)
with mock.patch(self.os_path_isfile_path) as isfile, \
mock.patch(self.os_access_path) as access, \
mock.patch(self.subprocess_popen_path) as popen, \
mock.patch(self.time_sleep_path), \
mock.patch(self.os_waitpid_path) as waitpid, \
self._mock_sbus_client('ping') as ping:
isfile.return_value = True
access.return_velue = True
popen.side_effect = [FakePopenObject(1000),
FakePopenObject(1001)]
waitpid.return_value = 0, 0
ping.return_value = SBusResponse(False, 'NG')
with self.assertRaises(SDaemonError):
self.dfactory.spawn_subprocess(
['arg0', 'argv1', 'argv2'],
{'envk0': 'envv0'}, 'storleta')
self.assertEqual(('arg0',), isfile.call_args[0])
self.assertEqual((1000, 1), waitpid.call_args[0])
self.assertEqual({'storleta': 1000},
self.dfactory.storlet_name_to_pid)
with mock.patch(self.os_path_isfile_path) as isfile, \
mock.patch(self.os_access_path) as access, \
mock.patch(self.subprocess_popen_path) as popen, \
mock.patch(self.time_sleep_path), \
mock.patch(self.os_waitpid_path) as waitpid:
isfile.return_value = True
access.return_velue = True
popen.side_effect = [FakePopenObject(1000),
FakePopenObject(1001)]
waitpid.return_value = 1000, -1
with self.assertRaises(SDaemonError):
self.dfactory.spawn_subprocess(
['arg0', 'argv1', 'argv2'],
{'envk0': 'envv0'}, 'storleta')
self.assertEqual(('arg0',), isfile.call_args[0])
self.assertEqual((1000, 1), waitpid.call_args[0])
with mock.patch(self.os_path_isfile_path) as isfile, \
mock.patch(self.subprocess_popen_path) as popen:
isfile.return_value = False
with self.assertRaises(SDaemonError):
self.dfactory.spawn_subprocess(
['arg0', 'argv1', 'argv2'],
{'envk0': 'envv0'}, 'storleta')
self.assertEqual(('arg0',), isfile.call_args[0])
popen.assert_not_called()
with mock.patch(self.os_path_isfile_path) as isfile, \
mock.patch(self.os_access_path) as access, \
mock.patch(self.subprocess_popen_path) as popen:
isfile.return_value = True
access.return_value = False
with self.assertRaises(SDaemonError):
self.dfactory.spawn_subprocess(
['arg0', 'argv1', 'argv2'],
{'envk0': 'envv0'}, 'storleta')
self.assertEqual(('arg0',), isfile.call_args[0])
popen.assert_not_called()
with mock.patch(self.os_path_isfile_path) as isfile, \
mock.patch(self.os_access_path) as access, \
mock.patch(self.subprocess_popen_path) as popen:
isfile.return_value = True
access.return_value = False
popen.side_effect = OSError()
with self.assertRaises(SDaemonError):
self.dfactory.spawn_subprocess(
['arg0', 'argv1', 'argv2'],
{'envk0': 'envv0'}, 'storleta')
self.assertEqual(('arg0',), isfile.call_args[0])
with mock.patch(self.os_path_isfile_path) as isfile:
with self.assertRaises(SDaemonError):
self.dfactory.spawn_subprocess([], {}, 'storleta')
self.assertEqual(0, isfile.call_count)
def test_wait_for_daemon_to_initialize(self):
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'path/to/uds/a'}
with self._mock_sbus_client('ping') as ping, \
mock.patch(self.time_sleep_path):
ping.return_value = SBusResponse(True, 'OK')
self.assertTrue(
self.dfactory.wait_for_daemon_to_initialize('storleta'))
self.assertEqual(1, ping.call_count)
with self._mock_sbus_client('ping') as ping, \
mock.patch(self.time_sleep_path):
ping.return_value = SBusResponse(False, 'NG')
self.assertFalse(
self.dfactory.wait_for_daemon_to_initialize('storleta'))
self.assertEqual(
self.dfactory.NUM_OF_TRIES_PINGING_STARTING_DAEMON,
ping.call_count)
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'path/to/uds/a', 'storletb': 'path/to/uds/b'}
with self._mock_sbus_client('ping') as ping, \
mock.patch(self.time_sleep_path):
ping.side_effect = SBusClientSendError()
self.assertFalse(
self.dfactory.wait_for_daemon_to_initialize('storleta'))
self.assertEqual(
self.dfactory.NUM_OF_TRIES_PINGING_STARTING_DAEMON,
ping.call_count)
def test_process_start_daemon(self):
# Not running
self.dfactory.storlet_name_to_pid = {}
self.dfactory.storlet_name_to_pipe_name = {}
class FakePopenObject(object):
def __init__(self, pid):
self.pid = pid
self.stderr = mock.MagicMock()
self.stdout = mock.MagicMock()
with mock.patch(self.os_path_isfile_path) as isfile, \
mock.patch(self.os_access_path) as access, \
mock.patch(self.subprocess_popen_path) as popen, \
mock.patch(self.time_sleep_path), \
mock.patch(self.os_waitpid_path) as waitpid, \
self._mock_sbus_client('ping') as ping:
isfile.return_value = True
access.return_value = True
popen.side_effect = [FakePopenObject(1000),
FakePopenObject(1001)]
waitpid.return_value = 0, 0
ping.return_value = SBusResponse(True, 'OK')
self.assertTrue(self.dfactory.process_start_daemon(
'java', 'path/to/storlet/a', 'storleta', 1, 'path/to/uds/a',
'TRACE'))
self.assertEqual({'storleta': 'path/to/uds/a'},
self.dfactory.storlet_name_to_pipe_name)
# Already running
self.dfactory.storlet_name_to_pid = {'storleta': 1000}
self.dfactory.storlet_name_to_pipe_name = {'storleta': 'path/to/uds/a'}
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.return_value = 0, 0
self.assertFalse(self.dfactory.process_start_daemon(
'java', 'path/to/storlet/a', 'storleta', 1, 'path/to/uds/a',
'TRACE'))
# Unsupported language
with self.assertRaises(SDaemonError):
self.dfactory.process_start_daemon(
'foo', 'path/to/storlet/a', 'storleta', 1, 'path/to/uds/a',
'TRACE')
def test_get_process_status_by_name(self):
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.return_value = 0, 0
self.assertTrue(
self.dfactory.get_process_status_by_name('storleta'))
self.assertEqual(1, waitpid.call_count)
self.assertEqual((1000, 1), waitpid.call_args[0])
self.assertFalse(
self.dfactory.get_process_status_by_name('storletc'))
def test_get_process_status_by_pid(self):
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.return_value = 0, 0
self.assertTrue(
self.dfactory.get_process_status_by_pid(1000, 'storleta'))
self.assertEqual(1, waitpid.call_count)
self.assertEqual((1000, 1), waitpid.call_args[0])
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.return_value = 1000, 0
self.assertFalse(
self.dfactory.get_process_status_by_pid(1000, 'storleta'))
self.assertEqual(1, waitpid.call_count)
self.assertEqual((1000, 1), waitpid.call_args[0])
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.side_effect = OSError(errno.ESRCH, '')
self.assertFalse(
self.dfactory.get_process_status_by_pid(1000, 'storleta'))
self.assertEqual(1, waitpid.call_count)
self.assertEqual((1000, 1), waitpid.call_args[0])
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.side_effect = OSError(errno.EPERM, '')
exc_pattern = ('^No permission to access the storlet daemon'
' storleta$')
with self.assertRaisesRegex(SDaemonError, exc_pattern):
self.dfactory.get_process_status_by_pid(1000, 'storleta')
self.assertEqual(1, waitpid.call_count)
self.assertEqual((1000, 1), waitpid.call_args[0])
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.side_effect = OSError()
exc_pattern = '^Unknown error$'
with self.assertRaisesRegex(SDaemonError, exc_pattern):
self.dfactory.get_process_status_by_pid(1000, 'storleta')
self.assertEqual(1, waitpid.call_count)
self.assertEqual((1000, 1), waitpid.call_args[0])
def test_process_kill(self):
# Success
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_kill_path) as kill, \
mock.patch(self.os_waitpid_path) as waitpid:
waitpid.return_value = 1000, 0
self.assertEqual((1000, 0),
self.dfactory.process_kill('storleta'))
self.assertEqual(1, kill.call_count)
self.assertEqual(1, waitpid.call_count)
self.assertEqual({'storletb': 1001},
self.dfactory.storlet_name_to_pid)
# When failed to send kill to the storlet daemon
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_kill_path) as kill, \
mock.patch(self.os_waitpid_path) as waitpid:
kill.side_effect = OSError()
with self.assertRaises(SDaemonError):
self.dfactory.process_kill('storleta')
self.assertEqual(1, kill.call_count)
self.assertEqual(0, waitpid.call_count)
self.assertEqual({'storleta': 1000, 'storletb': 1001},
self.dfactory.storlet_name_to_pid)
# When failed to wait
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_kill_path) as kill, \
mock.patch(self.os_waitpid_path) as waitpid:
waitpid.side_effect = OSError()
with self.assertRaises(SDaemonError):
self.dfactory.process_kill('storleta')
self.assertEqual(1, kill.call_count)
self.assertEqual(1, waitpid.call_count)
self.assertEqual({'storleta': 1000, 'storletb': 1001},
self.dfactory.storlet_name_to_pid)
# if the storlet daemon is not recognised
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_kill_path) as kill, \
mock.patch(self.os_waitpid_path) as waitpid:
with self.assertRaises(SDaemonError):
self.dfactory.process_kill('storletc')
self.assertEqual(0, kill.call_count)
self.assertEqual(0, waitpid.call_count)
self.assertEqual({'storleta': 1000, 'storletb': 1001},
self.dfactory.storlet_name_to_pid)
def test_process_kill_all(self):
# Success
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_kill_path) as kill, \
mock.patch(self.os_waitpid_path) as waitpid:
waitpid.side_effect = [(1000, 0), (1001, 0)]
self.dfactory.process_kill_all()
self.assertEqual(2, kill.call_count)
self.assertEqual(2, waitpid.call_count)
self.assertEqual({}, self.dfactory.storlet_name_to_pid)
# Success (no processes)
self.dfactory.storlet_name_to_pid = {}
with mock.patch(self.os_kill_path) as kill, \
mock.patch(self.os_waitpid_path) as waitpid:
self.dfactory.process_kill_all()
self.assertEqual(0, kill.call_count)
self.assertEqual(0, waitpid.call_count)
self.assertEqual({}, self.dfactory.storlet_name_to_pid)
# Failure (try_all = True)
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_kill_path) as kill, \
mock.patch(self.os_waitpid_path) as waitpid:
kill.side_effect = OSError()
exc_pattern = '^Failed to kill some storlet daemons: .*'
with self.assertRaisesRegex(SDaemonError, exc_pattern) as e:
self.dfactory.process_kill_all()
self.assertIn('storleta', str(e.exception))
self.assertIn('storletb', str(e.exception))
self.assertEqual(2, kill.call_count)
self.assertEqual(0, waitpid.call_count)
self.assertEqual({'storleta': 1000, 'storletb': 1001},
self.dfactory.storlet_name_to_pid)
# Failure (try_all = False)
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_kill_path) as kill, \
mock.patch(self.os_waitpid_path) as waitpid:
kill.side_effect = OSError()
exc_pattern = ('^Failed to send kill signal to the storlet daemon '
'storlet[a-b]$')
with self.assertRaisesRegex(SDaemonError, exc_pattern):
self.dfactory.process_kill_all(False)
self.assertEqual(1, kill.call_count)
self.assertEqual(0, waitpid.call_count)
self.assertEqual({'storleta': 1000, 'storletb': 1001},
self.dfactory.storlet_name_to_pid)
def test_shutdown_all_processes(self):
# Success
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'path/to/uds/a', 'storletb': 'path/to/uds/b'}
with self._mock_sbus_client('halt') as halt, \
mock.patch(self.os_waitpid_path):
halt.return_value = SBusResponse(True, 'OK')
terminated = self.dfactory.shutdown_all_processes()
self.assertEqual(2, len(terminated))
self.assertIn('storleta', terminated)
self.assertIn('storletb', terminated)
self.assertEqual({},
self.dfactory.storlet_name_to_pid)
# Failure (try_all = True)
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'patha', 'storletb': 'pathb'}
with self._mock_sbus_client('halt') as halt, \
mock.patch(self.os_waitpid_path) as waitpid:
halt.side_effect = SBusClientSendError()
exc_pattern = '^Failed to shutdown some storlet daemons: .*'
with self.assertRaisesRegex(SDaemonError, exc_pattern) as e:
self.dfactory.shutdown_all_processes()
self.assertIn('storleta', str(e.exception))
self.assertIn('storletb', str(e.exception))
self.assertEqual(2, halt.call_count)
self.assertEqual(0, waitpid.call_count)
self.assertEqual({'storleta': 1000, 'storletb': 1001},
self.dfactory.storlet_name_to_pid)
# Failure (try_all = False)
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'patha', 'storletb': 'pathb'}
with self._mock_sbus_client('halt') as halt, \
mock.patch(self.os_waitpid_path) as waitpid:
halt.side_effect = SBusClientSendError()
exc_pattern = ('^Failed to send halt command to the storlet '
'daemon storlet[a-b]$')
with self.assertRaisesRegex(SDaemonError, exc_pattern):
self.dfactory.shutdown_all_processes(False)
self.assertEqual(1, halt.call_count)
self.assertEqual(0, waitpid.call_count)
self.assertEqual({'storleta': 1000, 'storletb': 1001},
self.dfactory.storlet_name_to_pid)
def test_shutdown_process(self):
# Success
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'path/to/uds/a', 'storletb': 'path/to/uds/b'}
with self._mock_sbus_client('halt') as halt, \
mock.patch(self.os_waitpid_path):
halt.return_value = SBusResponse(True, 'OK')
self.dfactory.shutdown_process('storleta')
self.assertEqual({'storletb': 1001},
self.dfactory.storlet_name_to_pid)
# Failed to send a command to the storlet daemon
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'path/to/uds/a', 'storletb': 'path/to/uds/b'}
with self._mock_sbus_client('halt') as halt, \
mock.patch(self.os_waitpid_path) as waitpid:
halt.side_effect = SBusClientSendError()
with self.assertRaises(SDaemonError):
self.dfactory.shutdown_process('storleta')
self.assertEqual(0, waitpid.call_count)
self.assertEqual({'storleta': 1000, 'storletb': 1001},
self.dfactory.storlet_name_to_pid)
# Failed to wait
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'path/to/uds/a', 'storletb': 'path/to/uds/b'}
with self._mock_sbus_client('halt') as halt, \
mock.patch(self.os_waitpid_path) as waitpid:
halt.return_value = SBusResponse(True, 'OK')
waitpid.side_effect = OSError()
with self.assertRaises(SDaemonError):
self.dfactory.shutdown_process('storleta')
self.assertEqual({'storleta': 1000, 'storletb': 1001},
self.dfactory.storlet_name_to_pid)
# If the storlet is not found in pid mapping
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'path/to/uds/a', 'storletb': 'path/to/uds/b'}
with self.assertRaises(SDaemonError):
self.dfactory.shutdown_process('storletc')
def test_start_daemon(self):
prms = {'daemon_language': 'java',
'storlet_path': 'path/to/storlet/a',
'storlet_name': 'storleta',
'pool_size': 1,
'uds_path': 'path/to/uds/a',
'log_level': 'TRACE'}
# Not running
self.dfactory.storlet_name_to_pid = {}
self.dfactory.storlet_name_to_pipe_name = {}
class FakePopenObject(object):
def __init__(self, pid):
self.pid = pid
self.stderr = mock.MagicMock()
self.stdout = mock.MagicMock()
with mock.patch(self.os_path_isfile_path) as isfile, \
mock.patch(self.os_access_path) as access, \
mock.patch(self.subprocess_popen_path) as popen, \
mock.patch(self.time_sleep_path), \
mock.patch(self.os_waitpid_path) as waitpid, \
self._mock_sbus_client('ping') as ping, \
self._mock_sbus_client('start_daemon') as start_daemon:
isfile.return_value = True
access.return_value = True
popen.side_effect = [FakePopenObject(1000),
FakePopenObject(1001)]
waitpid.return_value = 0, 0
ping.return_value = SBusResponse(True, 'OK')
start_daemon.return_value = SBusResponse(True, 'OK')
ret = self.dfactory.start_daemon(DummyDatagram(prms))
self.assertTrue(ret.status)
self.assertEqual('OK', ret.message)
self.assertTrue(ret.iterable)
# Already running
self.dfactory.storlet_name_to_pid = {'storleta': 1000}
self.dfactory.storlet_name_to_pipe_name = {'storleta': 'path/to/uds/a'}
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.return_value = 0, 0
ret = self.dfactory.start_daemon(DummyDatagram(prms))
self.assertTrue(ret.status)
self.assertEqual(
'The storlet daemon storleta is already running', ret.message)
self.assertTrue(ret.iterable)
# Unsupported language
prms['daemon_language'] = 'foo'
ret = self.dfactory.start_daemon(DummyDatagram(prms))
self.assertFalse(ret.status)
self.assertEqual('Got unsupported daemon language: foo', ret.message)
self.assertTrue(ret.iterable)
def test_stop_daemon(self):
# Success
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000}
with mock.patch(self.os_kill_path), \
mock.patch(self.os_waitpid_path) as waitpid:
waitpid.return_value = 1000, 0
resp = self.dfactory.stop_daemon(
DummyDatagram({'storlet_name': 'storleta'}))
self.assertTrue(resp.status)
self.assertEqual('The storlet daemon storleta is stopped',
resp.message)
self.assertTrue(resp.iterable)
# Failure
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000}
with mock.patch(self.os_kill_path) as kill, \
mock.patch(self.os_waitpid_path):
kill.side_effect = OSError('ERROR')
resp = self.dfactory.stop_daemon(
DummyDatagram({'storlet_name': 'storleta'}))
self.assertFalse(resp.status)
self.assertEqual(
'Failed to send kill signal to the storlet daemon storleta',
resp.message)
self.assertTrue(resp.iterable)
def test_daemon_status(self):
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.return_value = 0, 0
resp = self.dfactory.daemon_status(
DummyDatagram({'storlet_name': 'storleta'}))
self.assertTrue(resp.status)
self.assertEqual('The storlet daemon storleta seems to be OK',
resp.message)
self.assertTrue(resp.iterable)
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.return_value = 1000, 0
resp = self.dfactory.daemon_status(
DummyDatagram({'storlet_name': 'storleta'}))
self.assertFalse(resp.status)
self.assertEqual('No running storlet daemons for storleta',
resp.message)
self.assertTrue(resp.iterable)
with mock.patch(self.os_waitpid_path) as waitpid:
waitpid.side_effect = OSError()
resp = self.dfactory.daemon_status(
DummyDatagram({'storlet_name': 'storleta'}))
self.assertFalse(resp.status)
self.assertEqual('Unknown error', resp.message)
self.assertTrue(resp.iterable)
def test_halt(self):
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
self.dfactory.storlet_name_to_pipe_name = \
{'storleta': 'path/to/uds/a', 'storletb': 'path/to/uds/b'}
with self._mock_sbus_client('halt') as halt, \
mock.patch(self.os_waitpid_path):
halt.return_value = SBusResponse(True, 'OK')
resp = self.dfactory.halt(DummyDatagram())
self.assertTrue(resp.status)
self.assertEqual(
'Stopped all storlet daemons. Terminating.', resp.message)
self.assertFalse(resp.iterable)
def test_stop_daemons(self):
# Success
self.dfactory.storlet_name_to_pid = \
{'storleta': 1000, 'storletb': 1001}
with mock.patch(self.os_kill_path), \
mock.patch(self.os_waitpid_path) as waitpid:
waitpid.side_effect = [(1000, 0), (1001, 0)]
resp = self.dfactory.stop_daemons(DummyDatagram())
self.assertTrue(resp.status)
self.assertEqual('OK', resp.message)
self.assertFalse(resp.iterable)
class TestSBusServerMain(test_server.TestSBusServerMain):
def _get_test_server(self):
return StorletDaemonFactory(self.sbus_path, self.logger, 'contid')
def test_main_loop_successful_stop(self):
# SBUS_CMD_HALT is for working to stop requested from
# storlet_middleware
self._test_main_loop_stop(sbus_cmd.SBUS_CMD_HALT)
def test_main_loop_timeout(self):
self._test_main_loop_timeout()
if __name__ == '__main__':
unittest.main()