diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py index 74c73b4f0e7c3a8faa383eff0dc2a2e121f7d645..2fc3ce11bcdeb5e1393b07867913c98fab3587a3 100644 --- a/src/device/service/DeviceServiceServicerImpl.py +++ b/src/device/service/DeviceServiceServicerImpl.py @@ -19,9 +19,9 @@ from .database.DatabaseTools import ( delete_device_from_context, get_device_driver_filter_fields, sync_device_from_context, sync_device_to_context, update_device_in_local_database) from .database.DeviceModel import DeviceModel, DriverModel -from .database.EndPointModel import EndPointModel +from .database.EndPointModel import EndPointModel, EndPointMonitorModel from .database.KpiModel import KpiModel -from .database.KpiSampleType import grpc_to_enum__kpi_sample_type +from .database.KpiSampleType import ORM_KpiSampleType, grpc_to_enum__kpi_sample_type from .driver_api._Driver import _Driver, RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES from .driver_api.DriverInstanceCache import DriverInstanceCache from .driver_api.Tools import ( @@ -109,26 +109,34 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): driver.Connect() endpoints = driver.GetConfig([RESOURCE_ENDPOINTS]) - #LOGGER.info('[AddDevice] endpoints = {:s}'.format(str(endpoints))) - for _, resource_value in endpoints: + LOGGER.info('[AddDevice] endpoints = {:s}'.format(str(endpoints))) + for resource_key, resource_value in endpoints: endpoint_uuid = resource_value.get('uuid') endpoint_type = resource_value.get('type') str_endpoint_key = key_to_str([device_uuid, endpoint_uuid]) - update_or_create_object( + db_endpoint, _ = update_or_create_object( self.database, EndPointModel, str_endpoint_key, { 'device_fk' : db_device, 'endpoint_uuid': endpoint_uuid, 'endpoint_type': endpoint_type, + 'resource_key' : resource_key, }) - - running_config_rules = driver.GetConfig([RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES]) + sample_types = resource_value.get('sample_types', {}) + for sample_type, monitor_resource_key in sample_types.items(): + str_endpoint_monitor_key = key_to_str([str_endpoint_key, str(sample_type)]) + update_or_create_object(self.database, EndPointMonitorModel, str_endpoint_monitor_key, { + 'endpoint_fk' : db_endpoint, + 'resource_key' : monitor_resource_key, + 'kpi_sample_type': grpc_to_enum__kpi_sample_type(sample_type), + }) + + running_config_rules = driver.GetConfig() running_config_rules = [ (ORM_ConfigActionEnum.SET, config_rule[0], json.dumps(config_rule[1], sort_keys=True)) for config_rule in running_config_rules ] #for running_config_rule in running_config_rules: # LOGGER.info('[AddDevice] running_config_rule: {:s}'.format(str(running_config_rule))) - update_config(self.database, device_uuid, 'running', running_config_rules) initial_config_rules = driver.GetInitialConfig() @@ -156,8 +164,8 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): request_config_rules = grpc_config_rules_to_raw(request.device_config.config_rules) #LOGGER.info('[ConfigureDevice] request_config_rules = {:s}'.format(str(request_config_rules))) - resources_to_set : List[Tuple[str, Any]] = [] # key, value - resources_to_delete : List[Tuple[str, Any]] = [] # key, value + resources_to_set : List[Tuple[str, Any]] = [] # key, value + resources_to_delete : List[Tuple[str, Any]] = [] # key, value for config_rule in request_config_rules: action, key, value = config_rule @@ -190,6 +198,15 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): if len(errors) > 0: raise OperationFailedException('ConfigureDevice', extra_details=errors) + running_config_rules = driver.GetConfig() + running_config_rules = [ + (ORM_ConfigActionEnum.SET, config_rule[0], json.dumps(config_rule[1], sort_keys=True)) + for config_rule in running_config_rules + ] + #for running_config_rule in running_config_rules: + # LOGGER.info('[AddDevice] running_config_rule: {:s}'.format(str(running_config_rule))) + update_config(self.database, device_uuid, 'running', running_config_rules) + sync_device_to_context(db_device, self.context_client) return DeviceId(**db_device.dump_id()) @@ -204,6 +221,9 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): self.driver_instance_cache.delete(device_uuid) delete_device_from_context(db_device, self.context_client) + for db_kpi_pk,_ in db_device.references(KpiModel): + KpiModel(self.database, db_kpi_pk).delete() + for db_endpoint_pk,_ in db_device.references(EndPointModel): EndPointModel(self.database, db_endpoint_pk).delete() @@ -252,6 +272,7 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): str_endpoint_key = key_to_str([str_endpoint_key, str_topology_key], separator=':') db_endpoint : EndPointModel = get_object( self.database, EndPointModel, str_endpoint_key, raise_if_not_found=False) + sampling_resource = db_endpoint.resource_key attributes = { 'kpi_uuid' : request.kpi_id.kpi_id.uuid, @@ -273,8 +294,6 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): msg = 'Device({:s}) has not been added to this Device instance'.format(str(device_uuid)) raise OperationFailedException('ConfigureDevice', extra_details=msg) - sampling_resource = driver.GetResource(db_endpoint.endpoint_uuid) - #resources_to_subscribe : List[Tuple[str, float, float]] = [] # key, sampling_duration, sampling_interval #resources_to_unsubscribe : List[Tuple[str, float, float]] = [] # key, sampling_duration, sampling_interval #LOGGER.info('[ConfigureDevice] resources_to_subscribe = {:s}'.format(str(resources_to_subscribe))) @@ -289,10 +308,12 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): # results_unsubscribestate = driver.UnsubscribeState(resources_to_unsubscribe) # errors.extend(check_unsubscribe_errors(resources_to_delete, results_unsubscribestate)) - results = driver.SubscribeState([ + subscriptions = [ (sampling_resource, db_kpi.sampling_duration, db_kpi.sampling_interval), - ]) - assert len(results) == 4 + ] + results = driver.SubscribeState(subscriptions) + LOGGER.info('results = {:s}'.format(str(results))) + assert len(results) == len(subscriptions) for result in results: assert isinstance(result, bool) and result self.monitoring_loops.add(device_uuid, driver) diff --git a/src/device/service/MonitoringLoops.py b/src/device/service/MonitoringLoops.py index 13842c00c571f6e3299a293f2eb11d1e5a5d78d9..7d71855883c63066c5f4c56afff38b1b5980b015 100644 --- a/src/device/service/MonitoringLoops.py +++ b/src/device/service/MonitoringLoops.py @@ -1,5 +1,8 @@ import logging, queue, threading from typing import Dict +from common.orm.Database import Database +from common.orm.HighLevel import get_object +from device.service.database.KpiModel import KpiModel from monitoring.client.monitoring_client import MonitoringClient from monitoring.proto.monitoring_pb2 import Kpi from .driver_api._Driver import _Driver @@ -8,7 +11,8 @@ LOGGER = logging.getLogger(__name__) QUEUE_GET_WAIT_TIMEOUT = 0.5 class MonitoringLoop: - def __init__(self, driver : _Driver, samples_queue : queue.Queue) -> None: + def __init__(self, device_uuid : str, driver : _Driver, samples_queue : queue.Queue) -> None: + self._device_uuid = device_uuid self._driver = driver self._samples_queue = samples_queue self._running = threading.Event() @@ -19,8 +23,7 @@ class MonitoringLoop: def _collect(self) -> None: for sample in self._samples_stream: if self._terminate.is_set(): break - LOGGER.info('[MonitoringLoop:_collect] sample={:s}'.format(str(sample))) - # TODO: add timestamp (if not present) + sample = (self._device_uuid, *sample) self._samples_queue.put_nowait(sample) def start(self): @@ -38,6 +41,7 @@ class MonitoringLoop: class MonitoringLoops: def __init__(self, monitoring_client : MonitoringClient) -> None: self._monitoring_client = monitoring_client + self._database = None self._samples_queue = queue.Queue() self._running = threading.Event() self._terminate = threading.Event() @@ -45,11 +49,14 @@ class MonitoringLoops: self._device_uuid__to__monitoring_loop : Dict[str, MonitoringLoop] = {} self._exporter_thread = threading.Thread(target=self._export, daemon=False) + def set_database(self, database : Database) -> None: + self._database = database + def add(self, device_uuid : str, driver : _Driver) -> None: with self._lock: monitoring_loop = self._device_uuid__to__monitoring_loop.get(device_uuid) if (monitoring_loop is not None) and monitoring_loop.is_running: return - monitoring_loop = MonitoringLoop(driver, self._samples_queue) + monitoring_loop = MonitoringLoop(device_uuid, driver, self._samples_queue) self._device_uuid__to__monitoring_loop[device_uuid] = monitoring_loop monitoring_loop.start() @@ -78,6 +85,8 @@ class MonitoringLoops: LOGGER.info('[MonitoringLoops:_export] sample={:s}'.format(str(sample))) except queue.Empty: continue - # TODO: find in database the KpiId, format KPI and send to Monitoring + + get_object(self._database, KpiModel) + self._database kpi_data = {} self._monitoring_client.IncludeKpi(Kpi(**kpi_data)) diff --git a/src/device/service/database/EndPointModel.py b/src/device/service/database/EndPointModel.py index 38b87d6f37c4e99dd3790f4d8802acd03873f77d..da10a67e676ca990f24cc1455bf6acc0999c1cc5 100644 --- a/src/device/service/database/EndPointModel.py +++ b/src/device/service/database/EndPointModel.py @@ -1,10 +1,12 @@ import logging from typing import Dict +from common.orm.fields.EnumeratedField import EnumeratedField from common.orm.fields.ForeignKeyField import ForeignKeyField from common.orm.fields.PrimaryKeyField import PrimaryKeyField from common.orm.fields.StringField import StringField from common.orm.model.Model import Model from .DeviceModel import DeviceModel +from .KpiSampleType import ORM_KpiSampleType from .TopologyModel import TopologyModel LOGGER = logging.getLogger(__name__) @@ -15,6 +17,7 @@ class EndPointModel(Model): device_fk = ForeignKeyField(DeviceModel) endpoint_uuid = StringField(required=True, allow_empty=False) endpoint_type = StringField() + resource_key = StringField(required=True, allow_empty=False) def dump_id(self) -> Dict: device_id = DeviceModel(self.database, self.device_fk).dump_id() @@ -31,3 +34,9 @@ class EndPointModel(Model): 'endpoint_id': self.dump_id(), 'endpoint_type': self.endpoint_type, } + +class EndPointMonitorModel(Model): + pk = PrimaryKeyField() + endpoint_fk = ForeignKeyField(EndPointModel) + resource_key = StringField(required=True, allow_empty=False) + kpi_sample_type = EnumeratedField(ORM_KpiSampleType, required=True) diff --git a/src/device/service/driver_api/AnyTreeTools.py b/src/device/service/driver_api/AnyTreeTools.py index df61c7e030a13a3d0d758ce51a011aaa95deb49f..47e80e6c71cadd1fb24a6aecb0309f8194a06756 100644 --- a/src/device/service/driver_api/AnyTreeTools.py +++ b/src/device/service/driver_api/AnyTreeTools.py @@ -1,5 +1,6 @@ import anytree from typing import Any, List, Optional +from apscheduler.job import Job class TreeNode(anytree.node.Node): def __init__(self, name, parent=None, children=None, **kwargs) -> None: @@ -45,7 +46,10 @@ def set_subnode_value(resolver : anytree.Resolver, root : TreeNode, path : List[ node = resolver.get(node, path_item) except anytree.ChildResolverError: node = TreeNode(path_item, parent=node) - node.value = value + if isinstance(node.value, dict) and isinstance(value, dict): + node.value.update(value) + else: + node.value = value def dump_subtree(root : TreeNode): if not isinstance(root, TreeNode): raise Exception('root must be a TreeNode') @@ -56,5 +60,6 @@ def dump_subtree(root : TreeNode): if len(path) == 0: continue value = node.value if value is None: continue + if isinstance(value, Job): value = str(value) results.append((path, value)) return results diff --git a/src/device/service/drivers/emulated/EmulatedDriver.py b/src/device/service/drivers/emulated/EmulatedDriver.py index f4599d7f0ad90ca185f052d0f92158cdde0c2e20..ae273890e29678f5fba9f3b8c84be88c65b3e142 100644 --- a/src/device/service/drivers/emulated/EmulatedDriver.py +++ b/src/device/service/drivers/emulated/EmulatedDriver.py @@ -1,3 +1,4 @@ +import json import anytree, logging, pytz, queue, random, threading from datetime import datetime, timedelta from typing import Any, Dict, Iterator, List, Optional, Tuple, Union @@ -6,6 +7,7 @@ from apscheduler.job import Job from apscheduler.jobstores.memory import MemoryJobStore from apscheduler.schedulers.background import BackgroundScheduler from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk_type +from device.service.database.KpiSampleType import ORM_KpiSampleType, grpc_to_enum__kpi_sample_type from device.service.driver_api._Driver import ( RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, _Driver) @@ -22,11 +24,27 @@ SPECIAL_RESOURCE_MAPPINGS = { def compose_resource_endpoint(endpoint_data : Dict[str, Any]) -> Tuple[str, Any]: endpoint_uuid = endpoint_data.get('uuid') if endpoint_uuid is None: return None - endpoint_type = endpoint_data.get('type') - if endpoint_type is None: return None endpoint_resource_path = SPECIAL_RESOURCE_MAPPINGS.get(RESOURCE_ENDPOINTS) endpoint_resource_key = '{:s}/endpoint[{:s}]'.format(endpoint_resource_path, endpoint_uuid) - endpoint_resource_value = {'uuid': endpoint_uuid, 'type': endpoint_type} + + endpoint_type = endpoint_data.get('type') + if endpoint_type is None: return None + + endpoint_sample_types = endpoint_data.get('sample_types') + if endpoint_sample_types is None: return None + sample_types = {} + for endpoint_sample_type in endpoint_sample_types: + try: + kpi_sample_type : ORM_KpiSampleType = grpc_to_enum__kpi_sample_type(endpoint_sample_type) + except: # pylint: disable=bare-except + LOGGER.warning('Unknown EndpointSampleType({:s}) for Endpoint({:s}). Ignoring and continuing...'.format( + str(endpoint_sample_type), str(endpoint_data))) + continue + metric_name = kpi_sample_type.name.lower() + monitoring_resource_key = '{:s}/state/{:s}'.format(endpoint_resource_key, metric_name) + sample_types[endpoint_sample_type] = monitoring_resource_key + + endpoint_resource_value = {'uuid': endpoint_uuid, 'type': endpoint_type, 'sample_types': sample_types} return endpoint_resource_key, endpoint_resource_value def do_sampling(resource_key : str, out_samples : queue.Queue): @@ -105,12 +123,6 @@ class EmulatedDriver(_Driver): results.extend(dump_subtree(resource_node)) return results - #def GetResource(self, endpoint_uuid : str) -> Optional[str]: - # chk_string('endpoint_uuid', endpoint_uuid) - # return { - # #'key': 'value', - # }.get(endpoint_uuid) - def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('resources', resources, list) if len(resources) == 0: return [] @@ -130,6 +142,11 @@ class EmulatedDriver(_Driver): results.append(e) # if validation fails, store the exception continue + try: + resource_value = json.loads(resource_value) + except: # pylint: disable=broad-except + pass + set_subnode_value(resolver, self.__running, resource_path, resource_value) results.append(True) return results diff --git a/src/device/tests/Device_Emulated.py b/src/device/tests/Device_Emulated.py index f1a143715b4a09d81e647c3025e50fc315cd2a54..1449ac2edb639e62c3827ceafb503fdbedebf9db 100644 --- a/src/device/tests/Device_Emulated.py +++ b/src/device/tests/Device_Emulated.py @@ -1,5 +1,6 @@ from copy import deepcopy from device.proto.context_pb2 import DeviceDriverEnum, DeviceOperationalStatusEnum +from device.service.database.KpiSampleType import ORM_KpiSampleType from .Tools import config_rule_set, config_rule_delete # use "deepcopy" to prevent propagating forced changes during tests @@ -20,39 +21,91 @@ DEVICE_EMU = { 'device_endpoints': [], } +PACKET_PORT_SAMPLE_TYPES = [ + ORM_KpiSampleType.PACKETS_TRANSMITTED.value, + ORM_KpiSampleType.PACKETS_RECEIVED.value, + ORM_KpiSampleType.BYTES_TRANSMITTED.value, + ORM_KpiSampleType.BYTES_RECEIVED.value, +] + DEVICE_EMU_ENDPOINTS = [ - ('EP1', '10Gbps'), - ('EP2', '10Gbps'), - ('EP3', '10Gbps'), - ('EP4', '10Gbps'), + ('EP1', '10Gbps', PACKET_PORT_SAMPLE_TYPES), + ('EP2', '10Gbps', PACKET_PORT_SAMPLE_TYPES), + ('EP3', '10Gbps', PACKET_PORT_SAMPLE_TYPES), + ('EP4', '10Gbps', PACKET_PORT_SAMPLE_TYPES), ] +RSRC_EP = '/endpoints/endpoint[{}]' +RSRC_SUBIF = RSRC_EP + '/subinterfaces/subinterface[{}]' +RSRC_ADDRIPV4 = RSRC_SUBIF + '/ipv4/address[{}]' + +DEVICE_EMU_ENDPOINTS_COOKED = [] +for endpoint_uuid,endpoint_type,endpoint_sample_types in DEVICE_EMU_ENDPOINTS: + endpoint_resource_key = RSRC_EP.format(str(endpoint_uuid)) + sample_types = { + ORM_KpiSampleType.PACKETS_TRANSMITTED.value: '{:s}/state/packets_transmitted'.format(endpoint_resource_key), + ORM_KpiSampleType.PACKETS_RECEIVED .value: '{:s}/state/packets_received' .format(endpoint_resource_key), + ORM_KpiSampleType.BYTES_TRANSMITTED .value: '{:s}/state/bytes_transmitted' .format(endpoint_resource_key), + ORM_KpiSampleType.BYTES_RECEIVED .value: '{:s}/state/bytes_received' .format(endpoint_resource_key), + } + endpoint_resource_value = {'uuid': endpoint_uuid, 'type': endpoint_type, 'sample_types': sample_types} + DEVICE_EMU_ENDPOINTS_COOKED.append((endpoint_resource_key, endpoint_resource_value)) + DEVICE_EMU_CONNECT_RULES = [ config_rule_set('_connect/address', DEVICE_EMU_ADDRESS ), config_rule_set('_connect/port', DEVICE_EMU_PORT ), config_rule_set('_connect/settings', {'endpoints': [ - {'uuid': endpoint_uuid, 'type': endpoint_type} - for endpoint_uuid,endpoint_type in DEVICE_EMU_ENDPOINTS + {'uuid': endpoint_uuid, 'type': endpoint_type, 'sample_types': endpoint_sample_types} + for endpoint_uuid,endpoint_type,endpoint_sample_types in DEVICE_EMU_ENDPOINTS ]}), ] -DEVICE_EMU_CONFIG_RULES = [ - config_rule_set('/dev/rsrc1/value', 'value1'), - config_rule_set('/dev/rsrc2/value', 'value2'), - config_rule_set('/dev/rsrc3/value', 'value3'), +DEVICE_EMU_CONFIG_ENDPOINTS = [ + config_rule_set(RSRC_EP.format('EP1'), {'enabled' : True}), + config_rule_set(RSRC_EP.format('EP2'), {'enabled' : True}), + config_rule_set(RSRC_EP.format('EP3'), {'enabled' : True}), + config_rule_set(RSRC_EP.format('EP4'), {'enabled' : True}), ] -DEVICE_EMU_RECONFIG_RULES = [ - config_rule_delete('/dev/rsrc1/value', ''), - config_rule_set ('/dev/rsrc10/value', 'value10'), - config_rule_set ('/dev/rsrc11/value', 'value11'), - config_rule_set ('/dev/rsrc12/value', 'value12'), +DEVICE_EMU_CONFIG_ADDRESSES = [ + config_rule_set(RSRC_SUBIF .format('EP1', 0 ), {'index': 0}), + config_rule_set(RSRC_ADDRIPV4.format('EP1', 0, '10.1.0.1'), {'ip': '10.1.0.1', 'prefix_length': 24}), + + config_rule_set(RSRC_SUBIF .format('EP2', 0 ), {'index': 0}), + config_rule_set(RSRC_ADDRIPV4.format('EP2', 0, '10.2.0.1'), {'ip': '10.2.0.1', 'prefix_length': 24}), + + config_rule_set(RSRC_SUBIF .format('EP3', 0 ), {'index': 0}), + config_rule_set(RSRC_ADDRIPV4.format('EP3', 0, '10.3.0.1'), {'ip': '10.3.0.1', 'prefix_length': 24}), + + config_rule_set(RSRC_SUBIF .format('EP4', 0 ), {'index': 0}), + config_rule_set(RSRC_ADDRIPV4.format('EP4', 0, '10.4.0.1'), {'ip': '10.4.0.1', 'prefix_length': 24}), +] + +DEVICE_EMU_RECONFIG_ADDRESSES = [ + config_rule_delete(RSRC_SUBIF .format('EP2', 0 ), {}), + config_rule_delete(RSRC_ADDRIPV4.format('EP2', 0, '10.2.0.1'), {'ip': '10.2.0.1', 'prefix_length': 24}), + + config_rule_set (RSRC_SUBIF .format('EP2', 1 ), {'index': 1}), + config_rule_set (RSRC_ADDRIPV4.format('EP2', 1, '10.2.1.1'), {'ip': '10.2.1.1', 'prefix_length': 24}), +] + +DEVICE_EMU_DECONFIG_ADDRESSES = [ + config_rule_delete(RSRC_SUBIF .format('EP1', 0 ), {}), + config_rule_delete(RSRC_ADDRIPV4.format('EP1', 0, '10.1.0.1'), {}), + + config_rule_delete(RSRC_SUBIF .format('EP2', 1 ), {}), + config_rule_delete(RSRC_ADDRIPV4.format('EP2', 1, '10.2.1.1'), {}), + + config_rule_delete(RSRC_SUBIF .format('EP3', 0 ), {}), + config_rule_delete(RSRC_ADDRIPV4.format('EP3', 0, '10.3.0.1'), {}), + + config_rule_delete(RSRC_SUBIF .format('EP4', 0 ), {}), + config_rule_delete(RSRC_ADDRIPV4.format('EP4', 0, '10.4.0.1'), {}), ] -DEVICE_EMU_DECONFIG_RULES = [ - config_rule_delete('/dev/rsrc2/value', 'value2'), - config_rule_delete('/dev/rsrc3/value', 'value3'), - config_rule_delete('/dev/rsrc10/value', 'value10'), - config_rule_delete('/dev/rsrc11/value', 'value11'), - config_rule_delete('/dev/rsrc12/value', 'value12'), +DEVICE_EMU_DECONFIG_ENDPOINTS = [ + config_rule_delete(RSRC_EP.format('EP1'), {}), + config_rule_delete(RSRC_EP.format('EP2'), {}), + config_rule_delete(RSRC_EP.format('EP3'), {}), + config_rule_delete(RSRC_EP.format('EP4'), {}), ] diff --git a/src/device/tests/test_unitary.py b/src/device/tests/test_unitary.py index 2b2b9115d19b15d9c657768fdd04da37cef9b45b..e9abe4eece8be8056727c8450e598af90a37e983 100644 --- a/src/device/tests/test_unitary.py +++ b/src/device/tests/test_unitary.py @@ -1,6 +1,6 @@ -import copy, grpc, json, logging, operator, os, pytest, time +import copy, grpc, json, logging, math, operator, os, pytest, time +from typing import Any, Dict, List, Tuple from queue import Queue, Empty -from typing import Tuple from google.protobuf.json_format import MessageToDict from common.orm.Database import Database from common.orm.Factory import get_database_backend, BackendEnum as DatabaseBackendEnum @@ -10,7 +10,7 @@ from context.Config import ( GRPC_SERVICE_PORT as CONTEXT_GRPC_SERVICE_PORT, GRPC_MAX_WORKERS as CONTEXT_GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD as CONTEXT_GRPC_GRACE_PERIOD) from context.client.ContextClient import ContextClient -from context.proto.context_pb2 import DeviceId +from context.proto.context_pb2 import DeviceId, DeviceOperationalStatusEnum from context.service.grpc_server.ContextService import ContextService from device.Config import ( GRPC_SERVICE_PORT as DEVICE_GRPC_SERVICE_PORT, GRPC_MAX_WORKERS as DEVICE_GRPC_MAX_WORKERS, @@ -21,7 +21,8 @@ from device.proto.device_pb2 import MonitoringSettings from device.proto.kpi_sample_types_pb2 import KpiSampleType from device.service.DeviceService import DeviceService from device.service.MonitoringLoops import MonitoringLoops -from device.service.driver_api._Driver import _Driver +from device.service.database.KpiSampleType import ORM_KpiSampleType +from device.service.driver_api._Driver import _Driver, RESOURCE_ENDPOINTS from device.service.driver_api.DriverFactory import DriverFactory from device.service.driver_api.DriverInstanceCache import DriverInstanceCache from device.service.drivers import DRIVERS @@ -33,8 +34,18 @@ from monitoring.Config import ( from monitoring.client.monitoring_client import MonitoringClient from .CommonObjects import CONTEXT, TOPOLOGY from .Device_Emulated import ( - DEVICE_EMU, DEVICE_EMU_CONFIG_RULES, DEVICE_EMU_CONNECT_RULES, DEVICE_EMU_DECONFIG_RULES, DEVICE_EMU_ENDPOINTS, DEVICE_EMU_ID, - DEVICE_EMU_RECONFIG_RULES, DEVICE_EMU_UUID) + DEVICE_EMU, + DEVICE_EMU_CONFIG_ADDRESSES, + DEVICE_EMU_CONFIG_ENDPOINTS, + DEVICE_EMU_CONNECT_RULES, + DEVICE_EMU_DECONFIG_ADDRESSES, + DEVICE_EMU_DECONFIG_ENDPOINTS, + DEVICE_EMU_ENDPOINTS, + DEVICE_EMU_ENDPOINTS_COOKED, + DEVICE_EMU_ID, + DEVICE_EMU_RECONFIG_ADDRESSES, + DEVICE_EMU_UUID, + RSRC_EP) try: from .Device_OpenConfig_Infinera import( DEVICE_OC, DEVICE_OC_CONFIG_RULES, DEVICE_OC_DECONFIG_RULES, DEVICE_OC_CONNECT_RULES, DEVICE_OC_ID, @@ -152,6 +163,9 @@ def test_prepare_environment( # ----- Test Device Driver Emulated ------------------------------------------------------------------------------------ +# Device Driver Emulated tests are used to validate Driver API as well as Emulated Device Driver. Note that other +# Drivers might support a different set of resource paths, and attributes/values per resource; however, they must +# implement the Driver API. def test_device_emulated_add_error_cases( context_client : ContextClient, # pylint: disable=redefined-outer-name @@ -161,7 +175,7 @@ def test_device_emulated_add_error_cases( with pytest.raises(grpc.RpcError) as e: DEVICE_EMU_WITH_EXTRA_RULES = copy.deepcopy(DEVICE_EMU) DEVICE_EMU_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONNECT_RULES) - DEVICE_EMU_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONFIG_RULES) + DEVICE_EMU_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONFIG_ENDPOINTS) device_client.AddDevice(Device(**DEVICE_EMU_WITH_EXTRA_RULES)) assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT msg_head = 'device.device_config.config_rules([' @@ -205,46 +219,78 @@ def test_device_emulated_configure( driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) LOGGER.info('driver_config = {:s}'.format(str(driver_config))) - assert len(driver_config) == len(DEVICE_EMU_ENDPOINTS) - for endpoint_uuid,endpoint_type in DEVICE_EMU_ENDPOINTS: - endpoint_resource_key = '/endpoints/endpoint[{:s}]'.format(str(endpoint_uuid)) - endpoint_resource_value = {'uuid': endpoint_uuid, 'type': endpoint_type} - assert (endpoint_resource_key, endpoint_resource_value) in driver_config + assert len(driver_config) == len(DEVICE_EMU_ENDPOINTS_COOKED) + for endpoint_cooked in DEVICE_EMU_ENDPOINTS_COOKED: + LOGGER.info('endpoint_cooked = {:s}'.format(str(endpoint_cooked))) + assert endpoint_cooked in driver_config DEVICE_EMU_WITH_CONFIG_RULES = copy.deepcopy(DEVICE_EMU) - DEVICE_EMU_WITH_CONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONFIG_RULES) + DEVICE_EMU_WITH_CONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONFIG_ENDPOINTS) device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_CONFIG_RULES)) + DEVICE_EMU_WITH_CONFIG_RULES = copy.deepcopy(DEVICE_EMU) + DEVICE_EMU_WITH_CONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONFIG_ADDRESSES) + device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_CONFIG_RULES)) + + DEVICE_EMU_WITH_OPERATIONAL_STATUS = copy.deepcopy(DEVICE_EMU) + DEVICE_EMU_WITH_OPERATIONAL_STATUS['device_operational_status'] = \ + DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED + device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_OPERATIONAL_STATUS)) + + driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) LOGGER.info('driver_config = {:s}'.format(str(driver_config))) - assert len(driver_config) == len(DEVICE_EMU_ENDPOINTS) + len(DEVICE_EMU_CONFIG_RULES) - for endpoint_uuid,endpoint_type in DEVICE_EMU_ENDPOINTS: - endpoint_resource_key = '/endpoints/endpoint[{:s}]'.format(str(endpoint_uuid)) - endpoint_resource_value = {'uuid': endpoint_uuid, 'type': endpoint_type} - assert (endpoint_resource_key, endpoint_resource_value) in driver_config - for config_rule in DEVICE_EMU_CONFIG_RULES: - assert (config_rule['resource_key'], config_rule['resource_value']) in driver_config + assert len(driver_config) == len(DEVICE_EMU_ENDPOINTS_COOKED) + len(DEVICE_EMU_CONFIG_ADDRESSES) + for endpoint_cooked in DEVICE_EMU_ENDPOINTS_COOKED: + endpoint_cooked = copy.deepcopy(endpoint_cooked) + endpoint_cooked[1]['enabled'] = True + LOGGER.info('endpoint_cooked = {:s}'.format(str(endpoint_cooked))) + assert endpoint_cooked in driver_config + for config_rule in DEVICE_EMU_CONFIG_ADDRESSES: + LOGGER.info('config_rule = {:s}'.format(str(config_rule))) + assert (config_rule['resource_key'], json.loads(config_rule['resource_value'])) in driver_config device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) + assert device_data.device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED + config_rules = [ (ConfigActionEnum.Name(config_rule.action), config_rule.resource_key, config_rule.resource_value) for config_rule in device_data.device_config.config_rules ] LOGGER.info('device_data.device_config.config_rules = \n{:s}'.format( '\n'.join(['{:s} {:s} = {:s}'.format(*config_rule) for config_rule in config_rules]))) - for config_rule in DEVICE_EMU_CONFIG_RULES: + RESULTING_CONFIG_ENDPOINTS = {cr['resource_key']:cr for cr in copy.deepcopy(DEVICE_EMU_CONFIG_ENDPOINTS)} + for endpoint_cooked in DEVICE_EMU_ENDPOINTS_COOKED: + values = json.loads(RESULTING_CONFIG_ENDPOINTS[endpoint_cooked[0]]['resource_value']) + values.update(endpoint_cooked[1]) + RESULTING_CONFIG_ENDPOINTS[endpoint_cooked[0]]['resource_value'] = json.dumps(values, sort_keys=True) + for config_rule in RESULTING_CONFIG_ENDPOINTS.values(): config_rule = ( - ConfigActionEnum.Name(config_rule['action']), config_rule['resource_key'], config_rule['resource_value']) + ConfigActionEnum.Name(config_rule['action']), config_rule['resource_key'], + json.loads(json.dumps(config_rule['resource_value']))) + assert config_rule in config_rules + for config_rule in DEVICE_EMU_CONFIG_ADDRESSES: + config_rule = ( + ConfigActionEnum.Name(config_rule['action']), config_rule['resource_key'], + json.loads(json.dumps(config_rule['resource_value']))) assert config_rule in config_rules + # Try to reconfigure... DEVICE_EMU_WITH_RECONFIG_RULES = copy.deepcopy(DEVICE_EMU) - DEVICE_EMU_WITH_RECONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_RECONFIG_RULES) + DEVICE_EMU_WITH_RECONFIG_RULES['device_operational_status'] = \ + DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED + DEVICE_EMU_WITH_RECONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_RECONFIG_ADDRESSES) device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_RECONFIG_RULES)) - RESULTING_CONFIG_RULES = {cr['resource_key']:cr for cr in copy.deepcopy(DEVICE_EMU_CONFIG_RULES)} - for reconfig_rule in DEVICE_EMU_RECONFIG_RULES: + RESULTING_CONFIG_RULES = {cr['resource_key']:cr for cr in copy.deepcopy(DEVICE_EMU_CONFIG_ENDPOINTS)} + for endpoint_cooked in DEVICE_EMU_ENDPOINTS_COOKED: + values = json.loads(RESULTING_CONFIG_RULES[endpoint_cooked[0]]['resource_value']) + values.update(endpoint_cooked[1]) + RESULTING_CONFIG_RULES[endpoint_cooked[0]]['resource_value'] = json.dumps(values, sort_keys=True) + RESULTING_CONFIG_RULES.update({cr['resource_key']:cr for cr in copy.deepcopy(DEVICE_EMU_CONFIG_ADDRESSES)}) + for reconfig_rule in DEVICE_EMU_RECONFIG_ADDRESSES: if reconfig_rule['action'] == ConfigActionEnum.CONFIGACTION_DELETE: RESULTING_CONFIG_RULES.pop(reconfig_rule['resource_key'], None) else: @@ -253,14 +299,13 @@ def test_device_emulated_configure( LOGGER.info('RESULTING_CONFIG_RULES = {:s}'.format(str(RESULTING_CONFIG_RULES))) driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + driver_config = json.loads(json.dumps(driver_config)) # prevent integer keys to fail matching with string keys LOGGER.info('driver_config = {:s}'.format(str(driver_config))) - assert len(driver_config) == len(DEVICE_EMU_ENDPOINTS) + len(RESULTING_CONFIG_RULES) - for endpoint_uuid,endpoint_type in DEVICE_EMU_ENDPOINTS: - endpoint_resource_key = '/endpoints/endpoint[{:s}]'.format(str(endpoint_uuid)) - endpoint_resource_value = {'uuid': endpoint_uuid, 'type': endpoint_type} - assert (endpoint_resource_key, endpoint_resource_value) in driver_config + assert len(driver_config) == len(RESULTING_CONFIG_RULES) for config_rule in RESULTING_CONFIG_RULES: - assert (config_rule['resource_key'], config_rule['resource_value']) in driver_config + resource = [config_rule['resource_key'], json.loads(config_rule['resource_value'])] + LOGGER.info('resource = {:s}'.format(str(resource))) + assert resource in driver_config device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) config_rules = [ @@ -272,46 +317,26 @@ def test_device_emulated_configure( for config_rule in RESULTING_CONFIG_RULES: config_rule = ( ConfigActionEnum.Name(config_rule['action']), config_rule['resource_key'], config_rule['resource_value']) + LOGGER.info('config_rule = {:s}'.format(str(config_rule))) assert config_rule in config_rules -def test_device_emulated_deconfigure( - context_client : ContextClient, # pylint: disable=redefined-outer-name - device_client : DeviceClient, # pylint: disable=redefined-outer-name - device_service : DeviceService): # pylint: disable=redefined-outer-name - - driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID) # we know the driver exists now - assert driver is not None - - driver_config = driver.GetConfig() - LOGGER.info('driver_config = {:s}'.format(str(driver_config))) - - DEVICE_EMU_WITH_DECONFIG_RULES = copy.deepcopy(DEVICE_EMU) - DEVICE_EMU_WITH_DECONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_DECONFIG_RULES) - device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_DECONFIG_RULES)) - - driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) - LOGGER.info('driver_config = {:s}'.format(str(driver_config))) - assert len(driver_config) == len(DEVICE_EMU_ENDPOINTS) - for endpoint_uuid,endpoint_type in DEVICE_EMU_ENDPOINTS: - endpoint_resource_key = '/endpoints/endpoint[{:s}]'.format(str(endpoint_uuid)) - endpoint_resource_value = {'uuid': endpoint_uuid, 'type': endpoint_type} - assert (endpoint_resource_key, endpoint_resource_value) in driver_config - - device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) - assert len(device_data.device_config.config_rules) == 0 - - def test_device_emulated_monitor( context_client : ContextClient, # pylint: disable=redefined-outer-name device_client : DeviceClient, # pylint: disable=redefined-outer-name device_service : DeviceService, # pylint: disable=redefined-outer-name monitoring_service : MockMonitoringService): # pylint: disable=redefined-outer-name - #device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) - #LOGGER.info('device_data = \n{:s}'.format(str(device_data))) + device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) + LOGGER.info('device_data = \n{:s}'.format(str(device_data))) + + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID) # we know the driver exists now + assert driver is not None + driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + assert len(driver_config) == len(DEVICE_EMU_ENDPOINTS_COOKED) + len(DEVICE_EMU_CONFIG_ADDRESSES) - SAMPLING_DURATION_SEC = 10.0 + SAMPLING_DURATION_SEC = 1.0 SAMPLING_INTERVAL_SEC = 0.5 NUM_SAMPLES_EXPECTED = SAMPLING_DURATION_SEC / SAMPLING_INTERVAL_SEC MONITORING_SETTINGS = { @@ -322,8 +347,8 @@ def test_device_emulated_monitor( 'device_id': DEVICE_EMU_ID, 'endpoint_id': endpoint_id(DEVICE_EMU_ID, 'EP2'), }, - 'sampling_duration_s': 10.0, - 'sampling_interval_s': 0.5, + 'sampling_duration_s': SAMPLING_DURATION_SEC, + 'sampling_interval_s': SAMPLING_INTERVAL_SEC, } # Start monitoring the device @@ -337,11 +362,63 @@ def test_device_emulated_monitor( while (len(received_samples) < NUM_SAMPLES_EXPECTED) and (time.time() - time_ini < SAMPLING_DURATION_SEC * 1.5): try: sample = queue_samples.get(block=True, timeout=SAMPLING_INTERVAL_SEC) + LOGGER.info('sample = {:s}'.format(str(sample))) received_samples.append(sample) except Empty: continue assert len(received_samples) == NUM_SAMPLES_EXPECTED + # TODO: Validate the received samples + LOGGER.info('received_samples = {:s}'.format(str(received_samples))) + raise Exception() + + + +def test_device_emulated_deconfigure( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID) # we know the driver exists now + assert driver is not None + + driver_config = driver.GetConfig() + LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + + DEVICE_EMU_WITH_DECONFIG_RULES = copy.deepcopy(DEVICE_EMU) + DEVICE_EMU_WITH_DECONFIG_RULES['device_operational_status'] = \ + DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED + DEVICE_EMU_WITH_DECONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_DECONFIG_ADDRESSES) + device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_DECONFIG_RULES)) + + RESULTING_CONFIG_RULES = {cr['resource_key']:cr for cr in copy.deepcopy(DEVICE_EMU_CONFIG_ENDPOINTS)} + for endpoint_cooked in DEVICE_EMU_ENDPOINTS_COOKED: + values = json.loads(RESULTING_CONFIG_RULES[endpoint_cooked[0]]['resource_value']) + values.update(endpoint_cooked[1]) + RESULTING_CONFIG_RULES[endpoint_cooked[0]]['resource_value'] = json.dumps(values, sort_keys=True) + RESULTING_CONFIG_RULES = RESULTING_CONFIG_RULES.values() + driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + driver_config = json.loads(json.dumps(driver_config)) # prevent integer keys to fail matching with string keys + LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + assert len(driver_config) == len(RESULTING_CONFIG_RULES) + LOGGER.info('RESULTING_CONFIG_RULES = {:s}'.format(str(RESULTING_CONFIG_RULES))) + for config_rule in RESULTING_CONFIG_RULES: + config_rule = [config_rule['resource_key'], json.loads(config_rule['resource_value'])] + LOGGER.info('config_rule = {:s}'.format(str(config_rule))) + assert config_rule in driver_config + + DEVICE_EMU_WITH_DECONFIG_RULES = copy.deepcopy(DEVICE_EMU) + DEVICE_EMU_WITH_DECONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_DECONFIG_ENDPOINTS) + device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_DECONFIG_RULES)) + + driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + driver_config = json.loads(json.dumps(driver_config)) # prevent integer keys to fail matching with string keys + LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + assert len(driver_config) == 0 + + device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) + assert len(device_data.device_config.config_rules) == 0 + def test_device_emulated_delete( context_client : ContextClient, # pylint: disable=redefined-outer-name diff --git a/src/device/tests/test_unitary_driverapi.py b/src/device/tests/test_unitary_driverapi.py index d570592b16c238d80675a70390f8f0677a952777..ef355155b381837f4e01a5d7eba502f45448cc79 100644 --- a/src/device/tests/test_unitary_driverapi.py +++ b/src/device/tests/test_unitary_driverapi.py @@ -1,44 +1,3 @@ -import copy, logging, math, pytest, time -from typing import Any, Dict, List -from device.service.driver_api._Driver import RESOURCE_ENDPOINTS -from device.service.drivers.emulated.EmulatedDriver import EmulatedDriver - -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) - -# Note: these tests are used to validate Driver API using the Emulated Device Driver. That means other Drivers might -# support a different set of attributes, resource paths, and values. However, they must implement the Driver API. - -PATH_IF = '/interfaces/interface[name="{}"]' -PATH_SUBIF = PATH_IF + '/subinterfaces/subinterface[index="{}"]' -PATH_ADDRIPV4 = PATH_SUBIF + '/ipv4/address[ip="{}"]' - -DEVICE_DRIVER_SETTINGS = {} -DEVICE_DRIVER_SETTINGS_ENDPOINTS : List[Dict[str, Any]] = DEVICE_DRIVER_SETTINGS.setdefault('endpoints', []) -DEVICE_DRIVER_SETTINGS_ENDPOINTS.append({'uuid': 'EP1', 'type': '10Gbps'}) -DEVICE_DRIVER_SETTINGS_ENDPOINTS.append({'uuid': 'EP2', 'type': '10Gbps'}) -DEVICE_DRIVER_SETTINGS_ENDPOINTS.append({'uuid': 'EP3', 'type': '10Gbps'}) -DEVICE_DRIVER_SETTINGS_ENDPOINTS.append({'uuid': 'EP4', 'type': '10Gbps'}) - -DEVICE_CONFIG_ENDPOINTS = [] -for endpoint in DEVICE_DRIVER_SETTINGS_ENDPOINTS: - endpoint_uuid = endpoint.get('uuid') - endpoint_type = endpoint.get('type') - endpoint_resource_key = '/endpoints/endpoint[{:s}]'.format(endpoint_uuid) - endpoint_resource_value = {'uuid': endpoint_uuid, 'type': endpoint_type} - DEVICE_CONFIG_ENDPOINTS.append((endpoint_resource_key, endpoint_resource_value)) - -DEVICE_CONFIG_IF1 = [] -DEVICE_CONFIG_IF1.append((PATH_IF .format('IF1' ), {'name' : 'IF1', 'enabled' : True})) -DEVICE_CONFIG_IF1.append((PATH_SUBIF .format('IF1', 0 ), {'index': 0})) -DEVICE_CONFIG_IF1.append((PATH_ADDRIPV4.format('IF1', 0, '10.1.0.1'), {'ip': '10.1.0.1', 'prefix_length': 24})) - -DEVICE_CONFIG_IF2 = [] -DEVICE_CONFIG_IF2.append((PATH_IF .format('IF2' ), {'name' : 'IF2', 'enabled' : True})) -DEVICE_CONFIG_IF2.append((PATH_SUBIF .format('IF2', 0 ), {'index': 0})) -DEVICE_CONFIG_IF2.append((PATH_ADDRIPV4.format('IF2', 0, '10.2.0.1'), {'ip': '10.2.0.1', 'prefix_length': 24})) -DEVICE_CONFIG_IF2.append((PATH_SUBIF .format('IF2', 1 ), {'index': 1})) -DEVICE_CONFIG_IF2.append((PATH_ADDRIPV4.format('IF2', 1, '10.2.1.1'), {'ip': '10.2.1.1', 'prefix_length': 24})) PATH_IF_TX_PKTS = PATH_IF + 'state/tx_packets_per_second' PATH_IF_RX_PKTS = PATH_IF + 'state/rx_packets_per_second' @@ -48,69 +7,6 @@ DEVICE_STATE_IF1_RX_PKTS = PATH_IF_RX_PKTS.format('IF1') DEVICE_STATE_IF2_TX_PKTS = PATH_IF_TX_PKTS.format('IF2') DEVICE_STATE_IF2_RX_PKTS = PATH_IF_RX_PKTS.format('IF2') -@pytest.fixture(scope='session') -def device_driverapi_emulated(): - _driver = EmulatedDriver('127.0.0.1', 0, **DEVICE_DRIVER_SETTINGS) - _driver.Connect() - yield _driver - _driver.Disconnect() - -def test_device_driverapi_emulated_setconfig( - device_driverapi_emulated : EmulatedDriver): # pylint: disable=redefined-outer-name - - results = device_driverapi_emulated.SetConfig(DEVICE_CONFIG_IF1) - LOGGER.info('results:\n{:s}'.format('\n'.join(map(str, results)))) - assert len(results) == len(DEVICE_CONFIG_IF1) - for result in results: assert isinstance(result, bool) and result - - results = device_driverapi_emulated.SetConfig(DEVICE_CONFIG_IF2) - LOGGER.info('results:\n{:s}'.format('\n'.join(map(str, results)))) - assert len(results) == len(DEVICE_CONFIG_IF2) - for result in results: assert isinstance(result, bool) and result - -def test_device_driverapi_emulated_getconfig( - device_driverapi_emulated : EmulatedDriver): # pylint: disable=redefined-outer-name - - stored_config = device_driverapi_emulated.GetConfig() - LOGGER.info('stored_config:\n{:s}'.format('\n'.join(map(str, stored_config)))) - assert len(stored_config) == len(DEVICE_CONFIG_ENDPOINTS) + len(DEVICE_CONFIG_IF1) + len(DEVICE_CONFIG_IF2) - for config_row in stored_config: - assert (config_row in DEVICE_CONFIG_ENDPOINTS) or (config_row in DEVICE_CONFIG_IF1) or \ - (config_row in DEVICE_CONFIG_IF2) - for config_row in DEVICE_CONFIG_ENDPOINTS: assert config_row in stored_config - for config_row in DEVICE_CONFIG_IF1: assert config_row in stored_config - for config_row in DEVICE_CONFIG_IF2: assert config_row in stored_config - - stored_config = device_driverapi_emulated.GetConfig([RESOURCE_ENDPOINTS]) - LOGGER.info('stored_config:\n{:s}'.format('\n'.join(map(str, stored_config)))) - assert len(stored_config) == len(DEVICE_CONFIG_ENDPOINTS) - for config_row in stored_config: assert config_row in DEVICE_CONFIG_ENDPOINTS - for config_row in DEVICE_CONFIG_ENDPOINTS: assert config_row in stored_config - - stored_config = device_driverapi_emulated.GetConfig([PATH_IF.format('IF2')]) - LOGGER.info('stored_config:\n{:s}'.format('\n'.join(map(str, stored_config)))) - assert len(stored_config) == len(DEVICE_CONFIG_IF2) - for config_row in stored_config: assert config_row in DEVICE_CONFIG_IF2 - for config_row in DEVICE_CONFIG_IF2: assert config_row in stored_config - -def test_device_driverapi_emulated_deleteconfig( - device_driverapi_emulated : EmulatedDriver): # pylint: disable=redefined-outer-name - - results = device_driverapi_emulated.DeleteConfig([(PATH_ADDRIPV4.format('IF2', 0, '10.2.0.1'), '')]) - LOGGER.info('results:\n{:s}'.format('\n'.join(map(str, results)))) - assert (len(results) == 1) and isinstance(results[0], bool) and results[0] - - stored_config = device_driverapi_emulated.GetConfig() - LOGGER.info('stored_config:\n{:s}'.format('\n'.join(map(str, stored_config)))) - - device_config_if2 = list(filter(lambda row: '10.2.0.1' not in row[0], copy.deepcopy(DEVICE_CONFIG_IF2))) - assert len(stored_config) == len(DEVICE_CONFIG_ENDPOINTS) + len(DEVICE_CONFIG_IF1) + len(device_config_if2) - for config_row in stored_config: - assert (config_row in DEVICE_CONFIG_ENDPOINTS) or (config_row in DEVICE_CONFIG_IF1) or \ - (config_row in device_config_if2) - for config_row in DEVICE_CONFIG_ENDPOINTS: assert config_row in stored_config - for config_row in DEVICE_CONFIG_IF1: assert config_row in stored_config - for config_row in device_config_if2: assert config_row in stored_config def test_device_driverapi_emulated_subscriptions( device_driverapi_emulated : EmulatedDriver): # pylint: disable=redefined-outer-name