Commit f3275587 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Merge branch 'feat/device-driver-api' into 'develop'

Integrate implementation of Device Driver API and minor common improvements

See merge request teraflow-h2020/controller!22
parents e2d4f240 8061ca55
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
# stages of the cicd pipeline
stages:
  - dependencies
  - build
  - test
  - unit_test
  - integ_test
  - dependencies
  - deploy
  - funct_test

+2 −1
Original line number Diff line number Diff line
@@ -17,7 +17,8 @@ coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
    context/tests/test_unitary.py

coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
    device/tests/test_unitary.py
    device/tests/test_unitary_driverapi.py \
    device/tests/test_unitary_service.py

coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
    service/tests/test_unitary.py
+54 −7
Original line number Diff line number Diff line
from typing import Any, Set, Union
from typing import Any, List, Set, Sized, Tuple, Union

def chk_none(name : str, value : Any) -> Any:
    if value is not None:
@@ -18,13 +18,60 @@ def chk_type(name : str, value : Any, type_or_types : Union[type, Set[type]] = s
        raise AttributeError(msg.format(str(name), str(value), type(value).__name__, str(type_or_types)))
    return value

def chk_string(name, value, allow_empty=False) -> str:
    chk_not_none(name, value)
def chk_length(
    name : str, value : Sized, allow_empty : bool = False,
    min_length : Union[int, None] = None, max_length : Union[int, None] = None,
    allowed_lengths : Union[None, int, Set[int], List[int], Tuple[int]] = None) -> Any:

    length = len(chk_type(name, value, Sized))

    allow_empty = chk_type('allow_empty for {}'.format(name), allow_empty, bool)
    if not allow_empty and length == 0:
        msg = '{}({}) is out of range: allow_empty({}) min_length({}) max_length({}) allowed_lengths({}).'
        raise AttributeError(msg.format(
            str(name), str(value), str(allow_empty), str(min_length), str(max_length), str(allowed_lengths)))


    if min_length is not None:
        min_length = chk_type('min_length for {}'.format(name), min_length, int)
        if length < min_length:
            msg = '{}({}) is out of range: allow_empty({}) min_length({}) max_length({}) allowed_lengths({}).'
            raise AttributeError(msg.format(
                str(name), str(value), str(allow_empty), str(min_length), str(max_length), str(allowed_lengths)))

    if max_length is not None:
        max_length = chk_type('max_length for {}'.format(name), max_length, int)
        if length > max_length:
            msg = '{}({}) is out of range: allow_empty({}) min_value({}) max_value({}) allowed_lengths({}).'
            raise AttributeError(msg.format(
                str(name), str(value), str(allow_empty), str(max_length), str(max_length), str(allowed_lengths)))

    if allowed_lengths is not None:
        chk_type('allowed_lengths for {}'.format(name), allowed_lengths, (int, set, list, tuple))
        if isinstance(allowed_lengths, int):
            fixed_length = allowed_lengths
            if length != fixed_length:
                msg = '{}({}) is out of range: allow_empty({}) min_value({}) max_value({}) allowed_lengths({}).'
                raise AttributeError(msg.format(
                    str(name), str(value), str(allow_empty), str(max_length), str(max_length), str(allowed_lengths)))
        else:
            for i in allowed_lengths: chk_type('allowed_lengths[#{}] for {}'.format(i, name), i, int)
            if length not in allowed_lengths:
                msg = '{}({}) is out of range: allow_empty({}) min_value({}) max_value({}) allowed_lengths({}).'
                raise AttributeError(msg.format(
                    str(name), str(value), str(allow_empty), str(max_length), str(max_length), str(allowed_lengths)))

    return value

def chk_string(
    name : str, value : Any, allow_empty : bool = False,
    min_length : Union[int, None] = None, max_length : Union[int, None] = None,
    allowed_lengths : Union[None, int, Set[int], List[int], Tuple[int]] = None) -> str:

    chk_type(name, value, str)
    if allow_empty: return value
    if len(value) == 0:
        msg = '{}({}) string is empty.'
        raise AttributeError(msg.format(str(name), str(value)))
    chk_length(
        name, value, allow_empty=allow_empty, min_length=min_length, max_length=max_length,
        allowed_lengths=allowed_lengths)
    return value

def chk_float(name, value, type_or_types=(int, float), min_value=None, max_value=None) -> float:
+26 −37
Original line number Diff line number Diff line
@@ -88,17 +88,16 @@ def test_delete_link_empty_uuid(context_client : ContextClient):
        copy_link_id['link_id']['uuid'] = ''
        context_client.DeleteLink(LinkId(**copy_link_id))
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    assert e.value.details() == 'link_id.link_id.uuid() string is empty.'
    msg = 'link_id.link_id.uuid() is out of range: '\
          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
    assert e.value.details() == msg

def test_add_link_already_exists(context_client : ContextClient):
    # should fail with link already exists
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        context_client.AddLink(Link(**LINK))
    assert e.value.code() == grpc.StatusCode.ALREADY_EXISTS
    msg = ' '.join([
        'Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1)',
        'already exists in the database.',
    ])
    msg = 'Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1) already exists in the database.'
    assert e.value.details() == msg

def test_delete_link(context_client : ContextClient):
@@ -113,10 +112,7 @@ def test_delete_link_not_existing(context_client : ContextClient):
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
        context_client.DeleteLink(LinkId(**LINK_ID))
    assert e.value.code() == grpc.StatusCode.NOT_FOUND
    msg = ' '.join([
        'Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1)',
        'does not exist in the database.'
    ])
    msg = 'Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1) does not exist in the database.'
    assert e.value.details() == msg

def test_add_link_uuid_empty(context_client : ContextClient):
@@ -126,7 +122,9 @@ def test_add_link_uuid_empty(context_client : ContextClient):
        copy_link['link_id']['link_id']['uuid'] = ''
        context_client.AddLink(Link(**copy_link))
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    assert e.value.details() == 'link.link_id.link_id.uuid() string is empty.'
    msg = 'link.link_id.link_id.uuid() is out of range: '\
          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
    assert e.value.details() == msg

def test_add_link_wrong_endpoint(context_client : ContextClient):
    # should fail with wrong endpoint context
@@ -135,11 +133,9 @@ def test_add_link_wrong_endpoint(context_client : ContextClient):
        copy_link['endpointList'][0]['topoId']['contextId']['contextUuid']['uuid'] = 'wrong-context'
        context_client.AddLink(Link(**copy_link))
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = ' '.join([
        'Context(wrong-context) in Endpoint(#0) of Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1)',
        'mismatches acceptable Contexts({\'admin\'}).',
        'Optionally, leave field empty to use predefined Context(admin).',
    ])
    msg = 'Context(wrong-context) in Endpoint(#0) of '\
          'Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1) mismatches acceptable Contexts({\'admin\'}). '\
          'Optionally, leave field empty to use predefined Context(admin).'
    assert e.value.details() == msg

    # should fail with wrong endpoint topology
@@ -148,12 +144,9 @@ def test_add_link_wrong_endpoint(context_client : ContextClient):
        copy_link['endpointList'][0]['topoId']['topoId']['uuid'] = 'wrong-topo'
        context_client.AddLink(Link(**copy_link))
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = ' '.join([
        'Context(admin)/Topology(wrong-topo)',
        'in Endpoint(#0) of Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1)',
        'mismatches acceptable Topologies({\'admin\'}).',
        'Optionally, leave field empty to use predefined Topology(admin).',
    ])
    msg = 'Context(admin)/Topology(wrong-topo) in Endpoint(#0) of '\
          'Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1) mismatches acceptable Topologies({\'admin\'}). '\
          'Optionally, leave field empty to use predefined Topology(admin).'
    assert e.value.details() == msg

    # should fail with device uuid is empty
@@ -162,7 +155,9 @@ def test_add_link_wrong_endpoint(context_client : ContextClient):
        copy_link['endpointList'][0]['dev_id']['device_id']['uuid'] = ''
        context_client.AddLink(Link(**copy_link))
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    assert e.value.details() == 'endpoint_id[#0].dev_id.device_id.uuid() string is empty.'
    msg = 'endpoint_id[#0].dev_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

    # should fail with wrong endpoint device
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
@@ -170,11 +165,8 @@ def test_add_link_wrong_endpoint(context_client : ContextClient):
        copy_link['endpointList'][0]['dev_id']['device_id']['uuid'] = 'wrong-device'
        context_client.AddLink(Link(**copy_link))
    assert e.value.code() == grpc.StatusCode.NOT_FOUND
    msg = ' '.join([
        'Context(admin)/Topology(admin)/Device(wrong-device)',
        'in Endpoint(#0) of Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1)',
        'does not exist in the database.',
    ])
    msg = 'Context(admin)/Topology(admin)/Device(wrong-device) in Endpoint(#0) of '\
          'Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1) does not exist in the database.'
    assert e.value.details() == msg

    # should fail with endpoint uuid is empty
@@ -183,7 +175,9 @@ def test_add_link_wrong_endpoint(context_client : ContextClient):
        copy_link['endpointList'][0]['port_id']['uuid'] = ''
        context_client.AddLink(Link(**copy_link))
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    assert e.value.details() == 'endpoint_id[#0].port_id.uuid() string is empty.'
    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

    # should fail with wrong endpoint port
    with pytest.raises(grpc._channel._InactiveRpcError) as e:
@@ -191,11 +185,8 @@ def test_add_link_wrong_endpoint(context_client : ContextClient):
        copy_link['endpointList'][0]['port_id']['uuid'] = 'wrong-port'
        context_client.AddLink(Link(**copy_link))
    assert e.value.code() == grpc.StatusCode.NOT_FOUND
    msg = ' '.join([
        'Context(admin)/Topology(admin)/Device(DEV1)/Port(wrong-port)',
        'in Endpoint(#0) of Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1)',
        'does not exist in the database.',
    ])
    msg = 'Context(admin)/Topology(admin)/Device(DEV1)/Port(wrong-port) in Endpoint(#0) of '\
          'Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1) does not exist in the database.'
    assert e.value.details() == msg

    # should fail with endpoint device duplicated
@@ -204,10 +195,8 @@ def test_add_link_wrong_endpoint(context_client : ContextClient):
        copy_link['endpointList'][1]['dev_id']['device_id']['uuid'] = 'DEV1'
        context_client.AddLink(Link(**copy_link))
    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
    msg = ' '.join([
        'Duplicated Context(admin)/Topology(admin)/Device(DEV1)',
        'in Endpoint(#1) of Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1).',
    ])
    msg = 'Duplicated Context(admin)/Topology(admin)/Device(DEV1) in Endpoint(#1) of '\
          'Context(admin)/Topology(admin)/Link(DEV1/EP2 ==> DEV2/EP1).'
    assert e.value.details() == msg

def test_add_link(context_client : ContextClient):
+1 −1
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ unit_test device:
    - sleep 5
    - docker ps -a
    - docker logs $IMAGE_NAME
    - docker exec -i $IMAGE_NAME bash -c "pytest --log-level=DEBUG --verbose $IMAGE_NAME/tests/test_unitary.py"
    - docker exec -i $IMAGE_NAME bash -c "pytest --log-level=DEBUG --verbose $IMAGE_NAME/tests/test_unitary_service.py $IMAGE_NAME/tests/test_unitary_driverapi.py"
  after_script:
    - docker stop $IMAGE_NAME
    - docker rm $IMAGE_NAME
Loading