#!/usr/bin/python3 import logging import unittest from staslib import conf, ctrl, timeparse, trid from pyfakefs.fake_filesystem_unittest import TestCase class TestController(ctrl.Controller): def _find_existing_connection(self): pass def _on_aen(self, aen: int): pass def _on_nvme_event(self, nvme_event): pass def reload_hdlr(self): pass class TestDc(ctrl.Dc): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._connected = True class Ctrl: def __init__(this): this.name = 'nvme666' def connected(this): return self._connected def disconnect(this): pass self._ctrl = Ctrl() def _find_existing_connection(self): pass def _on_aen(self, aen: int): pass def _on_nvme_event(self, nvme_event): pass def reload_hdlr(self): pass def set_connected(self, value): self._connected = value def connected(self): return self._connected class TestStaf: def is_avahi_reported(self, tid): return False def controller_unresponsive(self, tid): pass @property def tron(self): return True stafd_conf_1 = ''' [Global] tron=false hdr-digest=false data-digest=false kato=30 queue-size=128 reconnect-delay=10 ctrl-loss-tmo=600 disable-sqflow=false ignore-iface=false ip-family=ipv4+ipv6 pleo=enabled [Service Discovery] zeroconf=enabled [Discovery controller connection management] persistent-connections=true zeroconf-connections-persistence=10 seconds ''' stafd_conf_2 = ''' [Discovery controller connection management] zeroconf-connections-persistence=-1 ''' class Test(TestCase): '''Unit tests for class Controller''' def setUp(self): self.setUpPyfakefs() self.fs.create_file( '/etc/nvme/hostnqn', contents='nqn.2014-08.org.nvmexpress:uuid:01234567-0123-0123-0123-0123456789ab\n' ) self.fs.create_file('/etc/nvme/hostid', contents='01234567-89ab-cdef-0123-456789abcdef\n') self.fs.create_file( '/dev/nvme-fabrics', contents='instance=-1,cntlid=-1,transport=%s,traddr=%s,trsvcid=%s,nqn=%s,queue_size=%d,nr_io_queues=%d,reconnect_delay=%d,ctrl_loss_tmo=%d,keep_alive_tmo=%d,hostnqn=%s,host_traddr=%s,host_iface=%s,hostid=%s,disable_sqflow,hdr_digest,data_digest,nr_write_queues=%d,nr_poll_queues=%d,tos=%d,fast_io_fail_tmo=%d,discovery,dhchap_secret=%s,dhchap_ctrl_secret=%s\n', ) self.NVME_TID = trid.TID( { 'transport': 'tcp', 'traddr': '10.10.10.10', 'subsysnqn': 'nqn.1988-11.com.dell:SFSS:2:20220208134025e8', 'trsvcid': '8009', 'host-traddr': '1.2.3.4', 'host-iface': 'wlp0s20f3', } ) default_conf = { ('Global', 'tron'): False, ('Global', 'hdr-digest'): False, ('Global', 'data-digest'): False, ('Global', 'kato'): None, # None to let the driver decide the default ('Global', 'queue-size'): None, # None to let the driver decide the default ('Global', 'reconnect-delay'): None, # None to let the driver decide the default ('Global', 'ctrl-loss-tmo'): None, # None to let the driver decide the default ('Global', 'disable-sqflow'): None, # None to let the driver decide the default ('Global', 'persistent-connections'): True, ('Discovery controller connection management', 'persistent-connections'): True, ('Discovery controller connection management', 'zeroconf-connections-persistence'): timeparse.timeparse( '72hours' ), ('Global', 'ignore-iface'): False, ('Global', 'ip-family'): (4, 6), ('Global', 'pleo'): True, ('Service Discovery', 'zeroconf'): True, ('Controllers', 'controller'): list(), ('Controllers', 'exclude'): list(), } self.stafd_conf_file1 = '/etc/stas/stafd1.conf' self.fs.create_file(self.stafd_conf_file1, contents=stafd_conf_1) self.stafd_conf_file2 = '/etc/stas/stafd2.conf' self.fs.create_file(self.stafd_conf_file2, contents=stafd_conf_2) self.svcconf = conf.SvcConf(default_conf=default_conf) self.svcconf.set_conf_file(self.stafd_conf_file1) def tearDown(self): pass def test_cannot_instantiate_concrete_classes_if_abstract_method_are_not_implemented(self): # Make sure we can't instantiate the ABC directly (Abstract Base Class). class Controller(ctrl.Controller): pass self.assertRaises(TypeError, lambda: ctrl.Controller(tid=self.NVME_TID)) def test_get_device(self): controller = TestController(tid=self.NVME_TID, service=TestStaf()) self.assertEqual(controller._connect_attempts, 0) controller._try_to_connect() self.assertEqual(controller._connect_attempts, 1) self.assertEqual( controller.id, "(tcp, 10.10.10.10, 8009, nqn.1988-11.com.dell:SFSS:2:20220208134025e8, wlp0s20f3, 1.2.3.4)" ) # raise Exception(controller._connect_op) self.assertEqual( str(controller.tid), "(tcp, 10.10.10.10, 8009, nqn.1988-11.com.dell:SFSS:2:20220208134025e8, wlp0s20f3, 1.2.3.4)", ) self.assertEqual(controller.device, 'nvme?') self.assertEqual( controller.controller_id_dict(), { 'transport': 'tcp', 'traddr': '10.10.10.10', 'trsvcid': '8009', 'host-traddr': '1.2.3.4', 'host-iface': 'wlp0s20f3', 'subsysnqn': 'nqn.1988-11.com.dell:SFSS:2:20220208134025e8', 'device': 'nvme?', }, ) self.assertEqual( controller.info(), { 'transport': 'tcp', 'traddr': '10.10.10.10', 'subsysnqn': 'nqn.1988-11.com.dell:SFSS:2:20220208134025e8', 'trsvcid': '8009', 'host-traddr': '1.2.3.4', 'host-iface': 'wlp0s20f3', 'device': 'nvme?', 'connect attempts': '1', 'retry connect timer': '60.0s [off]', 'connect operation': "{'fail count': 0, 'completed': False, 'alive': True}", }, ) self.assertEqual( controller.details(), { 'dctype': '', 'cntrltype': '', 'connected': 'False', 'transport': 'tcp', 'traddr': '10.10.10.10', 'trsvcid': '8009', 'host-traddr': '1.2.3.4', 'host-iface': 'wlp0s20f3', 'subsysnqn': 'nqn.1988-11.com.dell:SFSS:2:20220208134025e8', 'device': 'nvme?', 'connect attempts': '1', 'retry connect timer': '60.0s [off]', 'hostid': '', 'hostnqn': '', 'model': '', 'serial': '', 'connect operation': "{'fail count': 0, 'completed': False, 'alive': True}", }, ) # print(controller._connect_op) self.assertEqual(controller.cancel(), None) self.assertEqual(controller.kill(), None) self.assertIsNone(controller.disconnect(lambda *args: None, True)) def test_connect(self): controller = TestController(tid=self.NVME_TID, service=TestStaf()) self.assertEqual(controller._connect_attempts, 0) controller._find_existing_connection = lambda: None with self.assertLogs(logger=logging.getLogger(), level='DEBUG') as captured: controller._try_to_connect() self.assertTrue(len(captured.records) > 0) self.assertTrue( captured.records[0] .getMessage() .startswith( "Controller._do_connect() - (tcp, 10.10.10.10, 8009, nqn.1988-11.com.dell:SFSS:2:20220208134025e8, wlp0s20f3, 1.2.3.4) Connecting to nvme control with cfg={" ) ) self.assertEqual(controller._connect_attempts, 1) def test_dlp_supp_opts_as_string(self): dlp_supp_opts = 0x7 opts = ctrl.dlp_supp_opts_as_string(dlp_supp_opts) self.assertEqual(['EXTDLPES', 'PLEOS', 'ALLSUBES'], opts) def test_ncc(self): dlpe = {'eflags': '4'} ncc = ctrl.get_ncc(ctrl.get_eflags(dlpe)) self.assertTrue(ncc) dlpe = {} ncc = ctrl.get_ncc(ctrl.get_eflags(dlpe)) self.assertFalse(ncc) def test_dc(self): self.svcconf.set_conf_file(self.stafd_conf_file1) controller = TestDc(TestStaf(), tid=self.NVME_TID) controller.set_connected(True) controller.origin = 'discovered' with self.assertLogs(logger=logging.getLogger(), level='DEBUG') as captured: controller.origin = 'blah' self.assertEqual(len(captured.records), 1) self.assertNotEqual(-1, captured.records[0].getMessage().find("Trying to set invalid origin to blah")) controller.set_connected(False) with self.assertLogs(logger=logging.getLogger(), level='DEBUG') as captured: controller.origin = 'discovered' self.assertEqual(len(captured.records), 1) self.assertNotEqual( -1, captured.records[0].getMessage().find("Controller is not responding. Will be removed by") ) self.svcconf.set_conf_file(self.stafd_conf_file2) with self.assertLogs(logger=logging.getLogger(), level='DEBUG') as captured: controller.origin = 'discovered' self.assertEqual(len(captured.records), 1) self.assertNotEqual(-1, captured.records[0].getMessage().find("Controller not responding. Retrying...")) controller.set_connected(True) with self.assertLogs(logger=logging.getLogger(), level='DEBUG') as captured: controller.disconnect(lambda *args: None, keep_connection=False) self.assertEqual(len(captured.records), 2) self.assertNotEqual(-1, captured.records[0].getMessage().find("nvme666: keep_connection=False")) self.assertNotEqual(-1, captured.records[1].getMessage().find("nvme666 - Disconnect initiated")) # def test_disconnect(self): if __name__ == '__main__': unittest.main()