Skip to content
test_unitary.py 13.3 KiB
Newer Older
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
import copy, grpc, logging, pytest
from google.protobuf.json_format import MessageToDict
from common.database.Factory import get_database, DatabaseEngineEnum
from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
from common.database.api.context.topology.device.OperationalStatus import OperationalStatus
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
from common.tests.Assertions import validate_device_id, validate_empty
from device.client.DeviceClient import DeviceClient
from device.proto.context_pb2 import Device, DeviceId
from device.service.DeviceService import DeviceService
from device.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD
port = 10000 + GRPC_SERVICE_PORT # avoid privileged ports

LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)

# use "copy.deepcopy" to prevent propagating forced changes during tests
CONTEXT_ID = {'contextUuid': {'uuid': DEFAULT_CONTEXT_ID}}
TOPOLOGY_ID = {'contextId': copy.deepcopy(CONTEXT_ID), 'topoId': {'uuid': DEFAULT_TOPOLOGY_ID}}
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
DEVICE_ID = {'device_id': {'uuid': 'DEV1'}}
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
DEVICE = {
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    'device_type': 'ROADM',
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    'device_config': {'device_config': '<config/>'},
    'devOperationalStatus': OperationalStatus.ENABLED.value,
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    'endpointList' : [
        {
            'port_id': {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': copy.deepcopy(DEVICE_ID), 'port_id': {'uuid' : 'EP2'}},
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            'port_type': 'WDM'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        },
        {
            'port_id': {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': copy.deepcopy(DEVICE_ID), 'port_id': {'uuid' : 'EP3'}},
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            'port_type': 'WDM'
        },
        {
            'port_id': {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': copy.deepcopy(DEVICE_ID), 'port_id': {'uuid' : 'EP4'}},
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            'port_type': 'WDM'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def device_database():
    _database = get_database(engine=DatabaseEngineEnum.INMEMORY)
    return _database

@pytest.fixture(scope='session')
def device_service(device_database):
    _service = DeviceService(
        device_database, port=port, max_workers=GRPC_MAX_WORKERS, grace_period=GRPC_GRACE_PERIOD)
    _service.start()
    yield _service
    _service.stop()

@pytest.fixture(scope='session')
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def device_client(device_service):
    _client = DeviceClient(address='127.0.0.1', port=port)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    yield _client
    _client.close()

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_add_device_wrong_attributes(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with device uuid is empty
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['device_id']['device_id']['uuid'] = ''
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'device.device_id.device_id.uuid() is out of range: '\
          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed

    # should fail with device type is empty
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['device_type'] = ''
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'device.device_type() is out of range: '\
          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed

    # should fail with wrong device operational status
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['devOperationalStatus'] = OperationalStatus.KEEP_STATE.value
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'Method(AddDevice) does not accept OperationalStatus(KEEP_STATE). '\
          'Permitted values for Method(AddDevice) are OperationalStatus([\'DISABLED\', \'ENABLED\']).'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.details() == msg

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_add_device_wrong_endpoint(device_client : DeviceClient):
    # should fail with unsupported endpoint context
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['endpointList'][0]['port_id']['topoId']['contextId']['contextUuid']['uuid'] = 'wrong-context'
        request = Device(**copy_device)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(request)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'Context(wrong-context) in Endpoint(#0) of '\
          'Context(admin)/Topology(admin)/Device(DEV1) mismatches acceptable Contexts({\'admin\'}). '\
          'Optionally, leave field empty to use predefined Context(admin).'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.details() == msg

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with unsupported endpoint topology
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['endpointList'][0]['port_id']['topoId']['topoId']['uuid'] = 'wrong-topo'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'Context(admin)/Topology(wrong-topo) in Endpoint(#0) of '\
          'Context(admin)/Topology(admin)/Device(DEV1) mismatches acceptable Topologies({\'admin\'}). '\
          'Optionally, leave field empty to use predefined Topology(admin).'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.details() == msg

    # should fail with wrong endpoint device
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['endpointList'][0]['port_id']['dev_id']['device_id']['uuid'] = 'wrong-device'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'Context(admin)/Topology(admin)/Device(wrong-device) in Endpoint(#0) of '\
          'Context(admin)/Topology(admin)/Device(DEV1) mismatches acceptable Devices({\'DEV1\'}). '\
          'Optionally, leave field empty to use predefined Device(DEV1).'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.details() == msg

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with endpoint port uuid is empty
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['endpointList'][0]['port_id']['port_id']['uuid'] = ''
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'endpoint_id[#0].port_id.uuid() is out of range: '\
          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with endpoint port type is empty
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['endpointList'][0]['port_type'] = ''
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'endpoint[#0].port_type() is out of range: '\
          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with duplicate port in device
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        copy_device['endpointList'][1]['port_id']['port_id']['uuid'] = 'EP2'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'Duplicated Context(admin)/Topology(admin)/Device(DEV1)/Port(EP2) in Endpoint(#1) of '\
          'Context(admin)/Topology(admin)/Device(DEV1).'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_add_device(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should work
    validate_device_id(MessageToDict(
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            device_client.AddDevice(Device(**DEVICE)),
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            including_default_value_fields=True, preserving_proto_field_name=True,
            use_integers_for_enums=False))

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_add_device_duplicate(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with device already exists
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.AddDevice(Device(**DEVICE))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.ALREADY_EXISTS
    msg = 'Context(admin)/Topology(admin)/Device(DEV1) already exists in the database.'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_delete_device_empty_uuid(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with device uuid is empty
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device_id = copy.deepcopy(DEVICE_ID)
        copy_device_id['device_id']['uuid'] = ''
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.DeleteDevice(DeviceId(**copy_device_id))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'device_id.device_id.uuid() is out of range: '\
          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_delete_device_not_found(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with device not found
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device_id = copy.deepcopy(DEVICE_ID)
        copy_device_id['device_id']['uuid'] = 'wrong-device-id'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.DeleteDevice(DeviceId(**copy_device_id))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.NOT_FOUND
    msg = 'Context(admin)/Topology(admin)/Device(wrong-device-id) does not exist in the database.'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_delete_device(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should work
    validate_empty(MessageToDict(
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            device_client.DeleteDevice(DeviceId(**DEVICE_ID)),
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            including_default_value_fields=True, preserving_proto_field_name=True,
            use_integers_for_enums=False))

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_configure_device_empty_device_uuid(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with device uuid is empty
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['device_id']['device_id']['uuid'] = ''
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.ConfigureDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'device.device_id.device_id.uuid() is out of range: '\
          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_configure_device_not_found(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with device not found
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['device_id']['device_id']['uuid'] = 'wrong-device-id'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.ConfigureDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.NOT_FOUND
    msg = 'Context(admin)/Topology(admin)/Device(wrong-device-id) does not exist in the database.'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_add_device_default_endpoint_context_topology_device(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should work
    copy_device = copy.deepcopy(DEVICE)
    copy_device['endpointList'][0]['port_id']['topoId']['contextId']['contextUuid']['uuid'] = ''
    copy_device['endpointList'][0]['port_id']['topoId']['topoId']['uuid'] = ''
    copy_device['endpointList'][0]['port_id']['dev_id']['device_id']['uuid'] = ''
    validate_device_id(MessageToDict(
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            device_client.AddDevice(Device(**copy_device)),
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            including_default_value_fields=True, preserving_proto_field_name=True,
            use_integers_for_enums=False))

Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_configure_device_wrong_attributes(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should fail with device type is wrong
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
        copy_device['device_type'] = 'wrong-type'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.ConfigureDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = 'Device(DEV1) has Type(ROADM) in the database. Cannot be changed to Type(wrong-type).'
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed

    # should fail with endpoints cannot be modified
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.ConfigureDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.details() == 'Endpoints belonging to Device(DEV1) cannot be modified.'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed

    # should fail with any change detected
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        copy_device = copy.deepcopy(DEVICE)
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        copy_device['device_config']['device_config'] = ''
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        copy_device['devOperationalStatus'] = OperationalStatus.KEEP_STATE.value
        copy_device['endpointList'].clear()
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
        device_client.ConfigureDevice(Device(**copy_device))
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.code() == grpc.StatusCode.ABORTED
    msg = 'Any change has been requested for Device(DEV1). '\
          'Either specify a new configuration or a new device operational status.'
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    assert e.value.details() == msg
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
def test_configure_device(device_client : DeviceClient):
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
    # should work
    copy_device = copy.deepcopy(DEVICE)
    copy_device['device_config']['device_config'] = '<new_config/>'
    copy_device['devOperationalStatus'] = OperationalStatus.DISABLED.value
    copy_device['endpointList'].clear()
    validate_device_id(MessageToDict(
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            device_client.ConfigureDevice(Device(**copy_device)),
Lluis Gifre Renom's avatar
Lluis Gifre Renom committed
            including_default_value_fields=True, preserving_proto_field_name=True,
            use_integers_for_enums=False))