powertrain-build/tests/interface/test_interface_service.py
olindgre 2ece01e1d7 Make powertrain-build not overlap with pybuild in site-packages
Change-Id: I7b59f3f04f0f787d35db0b9389f295bf1ad24f56
2024-09-17 10:25:04 +02:00

787 lines
27 KiB
Python

# Copyright 2024 Volvo Car Corporation
# Licensed under Apache 2.0.
import unittest
from unittest import mock
from pathlib import Path
from powertrain_build.interface.base import Signal
from powertrain_build.interface.service import ServiceFramework, get_service_list
from powertrain_build.interface.csp_api import MissingApi
SIGNAL_SPEC = (
"enum_0", # enum padding
"property1", # property
"Float32", # property_interface_type
"Float32", # variable_type
0, # offset
1, # factor
0, # default
1, # length
-100, # min
100, # max
False, # enum
0, # init
"Description", # description
"Nm", # unit
"API", # endpoint
"interface", # api
"properties", # variant
"Always", # strategy
False, # debug
False, # dependability
)
class TestFunctions(unittest.TestCase):
def test_get_service_list(self):
dummy_app = mock.MagicMock()
dummy_app.get_service_mapping = mock.MagicMock(
return_value={'interface': 'service'}
)
service_list = get_service_list(dummy_app)
expected_services = ("LIST(APPEND extra_libraries"
" ${SERVICE_LIBINTERFACE_SERVICE_PROXY})\n"
"LIST(APPEND EXTRA_INCLUDE_DIRS"
" ${SERVICE_INCLUDE_DIR})\n")
self.assertEqual(expected_services, service_list)
class TestSfw(unittest.TestCase):
def test_parse_definition(self):
spec = {
'services': {}
}
dummy_app = mock.MagicMock()
sfw = ServiceFramework(dummy_app)
sfw.read_translation = mock.MagicMock(return_value=spec)
sfw.parse_definition('no_file')
self.assertDictEqual(sfw.translations, {})
def test_add_signals(self):
dummy_app = mock.MagicMock()
sfw = ServiceFramework(dummy_app)
insignal1 = Signal("test_name_in1", None)
insignal2 = Signal("test_name_in2", None)
outsignal = Signal("test_name_out", None)
signal_spec = SIGNAL_SPEC
test_signal1 = list(signal_spec)
test_signal1[14] = "endpoint1"
test_signal_1 = tuple(test_signal1)
test_signal2 = list(signal_spec)
test_signal2[14] = "endpoint2"
test_signal_2 = tuple(test_signal2)
test_signal3 = list(signal_spec)
test_signal3[14] = "endpoint3"
test_signal_3 = tuple(test_signal3)
sfw.translations = {
"test_name_in1": {test_signal_1},
"test_name_in2": {test_signal_2},
"test_name_out": {test_signal_3},
}
sfw.add_signals([insignal1], "insignals")
expected = {
"app": {"insignals": {"test_name_in1"}, "outsignals": set()},
"api": {"insignals": set(), "outsignals": {"property1"}},
}
expected_signal_primitives_list = ["interface.properties.endpoint1.property1.insignals"]
self.assertDictEqual(expected, sfw.signal_names)
self.assertListEqual(expected_signal_primitives_list, sfw.signal_primitives_list)
sfw.add_signals([insignal2], "insignals")
expected = {
"app": {
"insignals": {"test_name_in1", "test_name_in2"},
"outsignals": set(),
},
"api": {"insignals": set(), "outsignals": {"property1"}},
}
self.assertDictEqual(expected, sfw.signal_names)
expected_signal_primitives_list = ["interface.properties.endpoint1.property1.insignals",
"interface.properties.endpoint2.property1.insignals"]
self.assertDictEqual(expected, sfw.signal_names)
self.assertListEqual(expected_signal_primitives_list, sfw.signal_primitives_list)
sfw.add_signals([outsignal], "outsignals")
expected = {
"app": {
"insignals": {"test_name_in1", "test_name_in2"},
"outsignals": {"test_name_out"},
},
"api": {"insignals": {"property1"}, "outsignals": {"property1"}},
}
self.assertDictEqual(expected, sfw.signal_names)
expected_signal_primitives_list = ["interface.properties.endpoint1.property1.insignals",
"interface.properties.endpoint2.property1.insignals",
"interface.properties.endpoint3.property1.outsignals"]
self.assertDictEqual(expected, sfw.signal_names)
self.assertListEqual(expected_signal_primitives_list, sfw.signal_primitives_list)
def test_check_group_mixed_signals(self):
dummy_app = mock.MagicMock()
sfw = ServiceFramework(dummy_app)
signal_spec = SIGNAL_SPEC
test_signal = list(signal_spec)
test_signal_1 = tuple(test_signal)
test_signal_2 = tuple(test_signal)
sfw.translations = {
"test_signal_1": {test_signal_1},
"test_signal_2": {test_signal_2}
}
sfw.signal_names["app"]["insignals"] = {
"test_signal_1",
}
sfw.signal_names["app"]["outsignals"] = {
"test_signal_2",
}
expected_message = "Signal endpoint API for interface contains both consumed and produced signals"
with self.assertRaises(AssertionError) as context:
sfw.check_endpoints()
self.assertEqual(expected_message, str(context.exception))
def test_missing_service(self):
dummy_app = mock.MagicMock()
dummy_app.get_service_mapping = mock.MagicMock(return_value={'other_interface': 'service'})
dummy_app.get_services_file = mock.MagicMock(return_value=Path('file'))
insignal1 = Signal("signal1", dummy_app)
insignal2 = Signal("signal2", dummy_app)
dummy_app.insignals = [insignal1, insignal2]
dummy_app.get_signal_properties = mock.MagicMock(
side_effect=[
{'type': 'Float32'},
{'type': 'Float32'}
]
)
sfw = ServiceFramework(dummy_app)
service_definitions = {
"interface": {
"properties": [
{
"API": [
{
"insignal": "signal1",
"property": "property1"
},
{
"insignal": "signal2",
"property": "property2"
},
]
}
]
}
}
expected_message = "Api interface missing from file"
with self.assertRaises(MissingApi) as context:
sfw.parse_api_definitions(service_definitions)
self.assertEqual(expected_message, context.exception.message)
def test_parse_api_definitions(self):
dummy_app = mock.MagicMock()
dummy_app.get_service_mapping = mock.MagicMock(return_value={'interface': 'service'})
dummy_app.insignals = [
Signal("signal1", None),
Signal("signal2", None),
Signal("signal3", None),
Signal("signal4", None),
Signal("signal5", None)
]
dummy_app.get_signal_properties = mock.MagicMock(
side_effect=[
{'type': 'Float32'},
{'type': 'Float32'},
{'type': 'Float32'},
{'type': 'Float32'},
{'type': 'Float32'}
]
)
sfw = ServiceFramework(dummy_app)
service_definitions = {
"interface": {
"properties": [
{
"API": [
{
"insignal": "signal1",
"property": "property1"
},
{
"insignal": "signal2",
"property": "property2"
},
],
"RAW_0": [
{
"insignal": "signal3",
}
],
"RAW_1": [
{
"insignal": "signal4",
"property": None
}
],
"RAW_2": [
{
"insignal": "signal5",
"property": ""
}
],
}
]
}
}
sfw.parse_api_definitions(service_definitions)
expected = {
'signal1': {('enum_0', 'property1', 'Float32', None, None, None, None, None, None, None,
None, 0, None, None, 'API', 'interface', 'properties', 'Always', False, False)},
'signal2': {('enum_0', 'property2', 'Float32', None, None, None, None, None, None, None,
None, 0, None, None, 'API', 'interface', 'properties', 'Always', False, False)},
'signal3': {('enum_0', None, 'Float32', None, None, None, None, None, None, None,
None, 0, None, None, 'RAW_0', 'interface', 'properties', 'Always', False, False)},
'signal4': {('enum_0', None, 'Float32', None, None, None, None, None, None, None,
None, 0, None, None, 'RAW_1', 'interface', 'properties', 'Always', False, False)},
'signal5': {('enum_0', None, 'Float32', None, None, None, None, None, None, None,
None, 0, None, None, 'RAW_2', 'interface', 'properties', 'Always', False, False)}
}
self.assertDictEqual(sfw.translations, expected)
def test_parse_property_definitions_output_strategies(self):
dummy_app = mock.MagicMock()
dummy_app.get_service_mapping = mock.MagicMock(return_value={'interface': 'service'})
outsignal1 = Signal("signal1", None)
outsignal2 = Signal("signal2", None)
outsignal3 = Signal("signal3", None)
dummy_app.get_signal_properties = mock.MagicMock(
side_effect=[
{'type': 'Float32'},
{'type': 'Float32'},
{'type': 'Float32'}
]
)
dummy_app.outsignals = [outsignal1, outsignal2, outsignal3]
sfw = ServiceFramework(dummy_app)
signal_definitions = {
"interface": [
{
"outsignal": "signal1",
"strategy": "Always" # Correct
},
{
"outsignal": "signal2",
"strategy": "OnChanged" # Not allowed for outsignals
},
{
"outsignal": "signal3",
"strategy": "NonExistent" # Invalid strategy
}
]
}
sfw.parse_property_definitions(signal_definitions, 'API', 'properties')
expected = {
'signal1': {(
'enum_0',
None,
'Float32',
None,
None,
None,
None,
None,
None,
None,
None,
0,
None,
None,
'API',
'interface',
'properties',
'Always',
False,
False
)},
'signal2': {(
'enum_0',
None,
'Float32',
None,
None,
None,
None,
None,
None,
None,
None,
0,
None,
None,
'API',
'interface',
'properties',
'Always',
False,
False
)},
'signal3': {(
'enum_0',
None,
'Float32',
None,
None,
None,
None,
None,
None,
None,
None,
0,
None,
None,
'API',
'interface',
'properties',
'Always',
False,
False
)}
}
self.assertEqual(sfw.translations, expected)
def test_parse_property_definitions_level_0(self):
dummy_app = mock.MagicMock()
dummy_app.get_service_mapping = mock.MagicMock(return_value={'interface': 'service'})
insignal1 = Signal("signal1", None)
dummy_app.get_signal_properties = mock.MagicMock(
side_effect=[
{'type': 'Float32'},
]
)
dummy_app.insignals = [insignal1]
sfw = ServiceFramework(dummy_app)
signal_definitions = {
"interface": [
{
"insignal": "signal1",
},
]
}
sfw.parse_property_definitions(signal_definitions, 'API', 'properties')
expected = {
'signal1': {(
'enum_0',
None,
'Float32',
None,
None,
None,
None,
None,
None,
None,
None,
0,
None,
None,
'API',
'interface',
'properties',
'Always',
False,
False
)}
}
self.assertEqual(sfw.translations, expected)
def test_parse_property_definitions_level_1(self):
dummy_app = mock.MagicMock()
insignal1 = Signal("signal1", None)
insignal2 = Signal("signal2", None)
dummy_app.get_signal_properties = mock.MagicMock(
side_effect=[
{'type': 'Float32'},
{'type': 'Float32'}
]
)
dummy_app.insignals = [insignal1, insignal2]
dummy_app.get_service_mapping = mock.MagicMock(return_value={'interface': 'service'})
sfw = ServiceFramework(dummy_app)
signal_definitions = {
"interface": [
{
"insignal": "signal1",
"property": "property1"
},
{
"insignal": "signal2",
"property": "property2"
}
]
}
sfw.parse_property_definitions(signal_definitions, 'API', 'properties')
expected = {
'signal1': {(
'enum_0',
'property1',
'Float32',
None,
None,
None,
None,
None,
None,
None,
None,
0,
None,
None,
'API',
'interface',
'properties',
'Always',
False,
False
)},
'signal2': {(
'enum_0',
'property2',
'Float32',
None,
None,
None,
None,
None,
None,
None,
None,
0,
None,
None,
'API',
'interface',
'properties',
'Always',
False,
False
)}
}
self.assertEqual(sfw.translations, expected)
def test_parse_property_definitions_level_x(self):
dummy_app = mock.MagicMock()
dummy_app.get_service_mapping = mock.MagicMock(return_value={'interface': 'service'})
dummy_app.get_signal_properties = mock.MagicMock(
return_value={'type': 'Float32'}
)
dummy_app.insignals = [
Signal("signal1", dummy_app),
Signal("signal2", dummy_app),
Signal("signal3", dummy_app),
Signal("signal4", dummy_app),
]
sfw = ServiceFramework(dummy_app)
signal_definitions = {
"interface": [
{
"insignal": "signal1",
"property": "property0.member0"
},
{
"insignal": "signal2",
"property": "property0.member1"
},
{
"insignal": "signal3",
"property": "property1.member0.member0"
},
{
"insignal": "signal4",
"property": "property1.member1.member0.member0"
},
]
}
sfw.parse_property_definitions(signal_definitions, 'API', 'properties')
expected = {
'signal1': {
(
'enum_0',
'property0.member0',
'Float32',
None,
None,
None,
None,
None,
None,
None,
None,
0,
None,
None,
'API',
'interface',
'properties',
'Always',
False,
False
)
},
'signal2': {(
'enum_0', 'property0.member1', 'Float32', None, None, None, None, None, None, None,
None, 0, None, None, 'API', 'interface', 'properties', 'Always', False, False
)},
'signal3': {(
'enum_0', 'property1.member0.member0', 'Float32', None, None, None, None, None, None,
None, None, 0, None, None, 'API', 'interface', 'properties', 'Always', False, False
)},
'signal4': {(
'enum_0', 'property1.member1.member0.member0', 'Float32', None, None, None, None, None, None,
None, None, 0, None, None, 'API', 'interface', 'properties', 'Always', False, False
)}
}
self.assertEqual(sfw.translations, expected)
def test_spec_to_dict(self):
dummy_app = mock.MagicMock()
dummy_app.get_service_mapping = mock.MagicMock(return_value={'interface': 'service'})
sfw = ServiceFramework(dummy_app)
result = sfw.spec_to_dict(
SIGNAL_SPEC,
'signal1'
)
expected = {
'api': 'interface',
'property_type': 'Float32',
'endpoint': 'API',
'default': 0,
'description': 'Description',
'factor': 1,
'init': 0,
'length': 1,
'offset': 0,
'property': 'property1',
'range': {'max': 100, 'min': -100},
'unit': 'Nm',
'variable': 'signal1',
'variable_type': 'Float32',
'variant': 'properties',
'strategy': 'Always',
'debug': False,
'dependability': False
}
self.assertDictEqual(result, expected)
def test_to_dict(self):
dummy_app = mock.MagicMock()
dummy_app.get_service_mapping = mock.MagicMock(return_value={'interface': 'service'})
dummy_app.get_signal_properties = mock.MagicMock(
return_value={'type': 'Float32'}
)
insignal1 = Signal("signal1", dummy_app)
insignal2 = Signal("signal2", dummy_app)
dummy_app.insignals = [insignal1, insignal2]
sfw = ServiceFramework(dummy_app)
service_definitions = {
"interface": {
"properties": [
{
"API": [
{
"insignal": "signal1",
"property": "property1"
},
{
"insignal": "signal2",
"property": "property2"
},
]
}
]
}
}
sfw.parse_api_definitions(service_definitions)
sfw.add_signals([insignal1, insignal2], 'insignals')
result = sfw.to_dict()
expected = {
'consumer': [
{
'api': 'interface',
'property_type': 'Float32',
'endpoint': 'API',
'default': None,
'description': None,
'factor': None,
'init': 0,
'length': None,
'offset': None,
'property': 'property1',
'range': {'max': None, 'min': None},
'unit': None,
'variable': 'signal1',
'variable_type': None,
'variant': 'properties',
'strategy': 'Always',
'debug': False,
'dependability': False
},
{
'api': 'interface',
'property_type': 'Float32',
'endpoint': 'API',
'default': None,
'description': None,
'factor': None,
'init': 0,
'length': None,
'offset': None,
'property': 'property2',
'range': {'max': None, 'min': None},
'unit': None,
'variable': 'signal2',
'variable_type': None,
'variant': 'properties',
'strategy': 'Always',
'debug': False,
'dependability': False
}
],
'producer': []
}
self.assertDictEqual(expected, result)
def test_to_model(self):
dummy_app = mock.MagicMock()
dummy_app.get_service_mapping = mock.MagicMock(return_value={'interface': 'service'})
insignal1 = Signal("signal1", dummy_app)
insignal2 = Signal("signal2", dummy_app)
dummy_app.insignals = [insignal1, insignal2]
dummy_app.get_signal_properties = mock.MagicMock(
return_value={
'type': 'Float32',
'description': 'test description',
'unit': 'test unit'
}
)
dummy_app.insignals = [insignal1, insignal2]
sfw = ServiceFramework(dummy_app)
inherit_properties = [
{"destination": "description", "source": "description"},
{"destination": "unit", "source": "unit"},
]
service_definitions = {
"interface": {
"properties": [
{
"API": [
{
"insignal": "signal1",
"property": "property1"
},
{
"insignal": "signal2",
"property": "property2"
},
],
"API2": [
{
"insignal": "signal1",
}
]
}
]
}
}
sfw.parse_api_definitions(service_definitions)
sfw.add_signals([insignal1, insignal2], 'insignals', inherit_properties)
expected = {
'description': {
'brief': 'Internal interface for associated application.',
'full': 'This interface should only be used by the associated application.'
},
'name': '',
'properties': [
{
'accessors': 'r-',
'description': {
'brief': 'API2',
'full': 'test description'},
'name': 'API2',
'type': 'Float32',
'unit': 'test unit'
},
{
'accessors': 'r-',
'description': {
'brief': 'API',
'full': 'Generated from project without custom '
'description'},
'name': 'API',
'type': 'API',
'unit': 'struct'
},
],
'types': [
{
'description': {
'brief': 'API',
'full': 'Generated from project without custom '
'description'},
'kind': 'struct',
'members': [{'name': 'property1', 'type': 'Float32'},
{'name': 'property2', 'type': 'Float32'}],
'name': 'API'}],
'version': '${SERVICE_VERSION}'
}
result = sfw.to_model('internal')
self.assertDictEqual(result, expected)
def test_properties_service_model(self):
dummy_app = mock.MagicMock()
dummy_app.get_signal_properties = mock.MagicMock(
return_value={'type': 'Float32'}
)
dummy_app.get_service_mapping = mock.MagicMock(return_value={'interface': 'service'})
insignal1 = Signal("signal1", dummy_app)
dummy_app.insignals = [insignal1]
sfw = ServiceFramework(dummy_app)
sfw.signal_names["app"]["insignals"] = {'signal1'}
sfw.translations = {
"signal1": {SIGNAL_SPEC},
}
properties, types = sfw.properties_service_model('internal')
expected_properties = [{
'name': 'API',
'type': 'API',
'unit': 'struct',
'accessors': 'r-',
'description': {
'brief': 'API',
'full': 'Generated from project without custom description'
}
}]
expected_types = [{
'name': 'API',
'kind': 'struct',
'description': {
'brief': 'API',
'full': 'Generated from project without custom description'},
'members': [{'name': 'property1', 'type': 'Float32'}]
}]
self.assertCountEqual(properties, expected_properties)
self.assertCountEqual(types, expected_types)