Skip to content

Commit fde8c61

Browse files
Oleksandr Muzyka (EPAM)Oleksandr Muzyka (EPAM)
authored andcommitted
Add SAMM version validation to SAMMGraph load_aspect_model
1 parent 6f4fcac commit fde8c61

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/samm_graph.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,41 @@ def load_aspect_model(self) -> Aspect:
213213

214214
graph = self.rdf_graph + self.samm_graph
215215
self._reader.prepare_aspect_model(graph)
216+
self._validate_samm_namespace_version(graph)
216217

217218
model_element_factory = ModelElementFactory(self.samm_version, graph, self._cache)
218219
self.aspect = model_element_factory.create_element(aspect_urn)
219220

220221
return self.aspect
221222

223+
def _validate_samm_namespace_version(self, graph: Graph) -> None:
224+
"""
225+
Validates that the SAMM version in the given RDF graph matches the detected SAMM version.
226+
227+
This method iterates through the namespaces in the RDF graph and checks if any namespace
228+
corresponds to the SAMM namespace prefix. If a SAMM namespace is found, it extracts the version
229+
from the namespace and compares it to the `samm_version` attribute of the class. If the versions
230+
do not match, a `ValueError` is raised.
231+
232+
Args:
233+
graph (Graph): The RDF graph whose namespaces are to be validated.
234+
235+
Raises:
236+
ValueError: If the SAMM version in the graph's namespace does not match the detected SAMM version.
237+
"""
238+
for prefix, namespace in graph.namespace_manager.namespaces():
239+
if prefix.startswith(self.samm_namespace_prefix):
240+
namespace_info = namespace.split(":") # [urn, namespace_id, namespace_specific_str, entity, version#]
241+
242+
if len(namespace_info) == 5 and namespace_info[2] == "org.eclipse.esmf.samm":
243+
version = namespace_info[-1].replace("#", "")
244+
245+
if version != self.samm_version:
246+
raise ValueError(
247+
f"SAMM version mismatch. Found '{version}', but expected '{self.samm_version}'. "
248+
"Ensure all RDF files use a single, consistent SAMM version"
249+
)
250+
222251
def _get_aspect_from_elements(self):
223252
"""Geta and save the Aspect element from the model elements."""
224253
if self.model_elements:

core/esmf-aspect-meta-model-python/tests/unit/loader/test_samm_graph.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,10 @@ def test_load_aspect_model(self):
216216

217217
@mock.patch("esmf_aspect_meta_model_python.loader.samm_graph.ModelElementFactory")
218218
@mock.patch("esmf_aspect_meta_model_python.loader.samm_graph.SAMMGraph.get_aspect_urn")
219-
def test_load_aspect_model_create_element(self, get_aspect_urn_mock, model_element_factory_mock):
219+
@mock.patch("esmf_aspect_meta_model_python.loader.samm_graph.SAMMGraph._validate_samm_namespace_version")
220+
def test_load_aspect_model_create_element(
221+
self, validate_samm_namespace_version_mock, get_aspect_urn_mock, model_element_factory_mock
222+
):
220223
reader_mock = mock.MagicMock(name="reader")
221224
cache_mock = mock.MagicMock(name="cache")
222225
samm_graph = SAMMGraph()
@@ -229,13 +232,53 @@ def test_load_aspect_model_create_element(self, get_aspect_urn_mock, model_eleme
229232
get_aspect_urn_mock.return_value = "aspect_urn"
230233
model_element_factory_mock.return_value = model_element_factory_mock
231234
model_element_factory_mock.create_element.return_value = "aspect"
235+
232236
result = samm_graph.load_aspect_model()
233237

234238
assert result == "aspect"
235239
get_aspect_urn_mock.assert_called_once()
236240
reader_mock.prepare_aspect_model.assert_called_once_with("rdf_graph_samm_graph")
237241
model_element_factory_mock.assert_called_once_with("1.2.3", "rdf_graph_samm_graph", cache_mock)
238242
model_element_factory_mock.create_element.assert_called_once_with("aspect_urn")
243+
validate_samm_namespace_version_mock.assert_called_once_with("rdf_graph_samm_graph")
244+
245+
class TestValidateSammNamespaceVersion:
246+
"""Test suite for SAMMGraph._validate_samm_namespace_version method."""
247+
248+
def test_valid_version(self):
249+
version = "1.2.3"
250+
samm_graph = SAMMGraph()
251+
samm_graph.samm_version = version
252+
graph = mock.MagicMock(name="rdf_graph")
253+
graph.namespace_manager.namespaces.return_value = [
254+
("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
255+
("samm", f"urn:samm:org.eclipse.esmf.samm:meta-model:{version}#"), # True
256+
("samm1", f"urn:samm:org.eclipse.esmf.samm:{version}#"),
257+
("samm-e1", f"urn:samm:org.eclipse.esmf.samm:entity:{version}#"), # True
258+
("samm-c1", "urn:samm:org.china.zes.samm:extension:1.1.1#"),
259+
]
260+
261+
# Should not raise an exception
262+
samm_graph._validate_samm_namespace_version(graph)
263+
264+
def test_version_mismatch(self):
265+
samm_version = "2.2.0"
266+
earlier_version = "2.1.0"
267+
samm_graph = SAMMGraph()
268+
samm_graph.samm_version = samm_version
269+
graph = mock.MagicMock(name="rdf_graph")
270+
graph.namespace_manager.namespaces.return_value = [
271+
("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
272+
("samm", f"urn:samm:org.eclipse.esmf.samm:meta-model:{samm_version}#"),
273+
("samm-e1", f"urn:samm:org.eclipse.esmf.samm:extension:{earlier_version}#"), # Exception
274+
]
275+
276+
with pytest.raises(
277+
ValueError,
278+
match=f"SAMM version mismatch. Found '{earlier_version}', but expected '{samm_version}'. "
279+
"Ensure all RDF files use a single, consistent SAMM version",
280+
):
281+
samm_graph._validate_samm_namespace_version(graph)
239282

240283
def test_load_model_elements(self):
241284
samm_graph = SAMMGraph()

0 commit comments

Comments
 (0)