From c11f46410c3eb6aaf1ca32e20473e8a260461737 Mon Sep 17 00:00:00 2001 From: Samir Romdhani Date: Mon, 15 Jan 2024 18:37:50 +0100 Subject: [PATCH] feat(#373): remove restriction on AccessPoint name Signed-off-by: Samir Romdhani --- .../compas/sct/app/SclAutomationService.java | 2 +- .../SclAutomationServiceTest.java | 8 +- .../compas/sct/commons/SclService.java | 58 ++++++++++- .../compas/sct/commons/api/SclEditor.java | 11 ++- .../compas/sct/commons/SclServiceTest.java | 99 +++++++++++++++++-- .../lfenergy/compas/sct/commons/dto/DTO.java | 4 - .../scd_without_communication.xml | 13 +++ .../std_with_communication.xml | 18 ++++ .../std_with_full_filled_communication.xml | 30 ++++++ .../std_without_communication.xml | 13 +++ 10 files changed, 233 insertions(+), 23 deletions(-) create mode 100644 sct-commons/src/test/resources/scl_update_communication/scd_without_communication.xml create mode 100644 sct-commons/src/test/resources/scl_update_communication/std_with_communication.xml create mode 100644 sct-commons/src/test/resources/scl_update_communication/std_with_full_filled_communication.xml create mode 100644 sct-commons/src/test/resources/scl_update_communication/std_without_communication.xml diff --git a/sct-app/src/main/java/org/lfenergy/compas/sct/app/SclAutomationService.java b/sct-app/src/main/java/org/lfenergy/compas/sct/app/SclAutomationService.java index 76e0795e4..38ace789a 100644 --- a/sct-app/src/main/java/org/lfenergy/compas/sct/app/SclAutomationService.java +++ b/sct-app/src/main/java/org/lfenergy/compas/sct/app/SclAutomationService.java @@ -57,7 +57,7 @@ public SCL createSCD(@NonNull SCL ssd, @NonNull HeaderDTO headerDTO, List s sclEditor.addHistoryItem(scd, hItem.getWho(), hItem.getWhat(), hItem.getWhy()); } substationEditor.addSubstation(scd, ssd); - sclEditor.importSTDElementsInSCD(scd, stds, SUB_NETWORK_TYPES); + sclEditor.importSTDElementsInSCD(scd, stds); controlBlockEditor.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scd); return scd; } diff --git a/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceTest.java b/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceTest.java index 6c511c927..d33199d9b 100644 --- a/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceTest.java +++ b/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceTest.java @@ -83,7 +83,7 @@ void createSCD_without_headerHistory_should_return_generatedSCD() throws Invocat verify(sclEditor, times(1)).initScl(headerDTO.getId(), headerDTO.getVersion(), headerDTO.getRevision()); verify(sclEditor, times(0)).addHistoryItem(any(SCL.class), anyString(), anyString(), anyString()); verify(substationEditor, times(1)).addSubstation(any(SCL.class), any(SCL.class)); - verify(sclEditor, times(1)).importSTDElementsInSCD(any(SCL.class), anyList(), anyList()); + verify(sclEditor, times(1)).importSTDElementsInSCD(any(SCL.class), anyList()); verify(controlBlockEditor, times(1)).removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(any(SCL.class)); } @@ -112,7 +112,7 @@ void createSCD_with_headerHistory_should_return_generatedSCD() throws Invocation verify(sclEditor, times(1)).initScl(headerDTO.getId(), headerDTO.getVersion(), headerDTO.getRevision()); verify(sclEditor, times(1)).addHistoryItem(any(SCL.class), eq(historyItem.getWho()), eq(historyItem.getWhat()), eq(historyItem.getWhy())); verify(substationEditor, times(1)).addSubstation(any(SCL.class), any(SCL.class)); - verify(sclEditor, times(1)).importSTDElementsInSCD(any(SCL.class), anyList(), anyList()); + verify(sclEditor, times(1)).importSTDElementsInSCD(any(SCL.class), anyList()); verify(controlBlockEditor, times(1)).removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(any(SCL.class)); } @@ -167,7 +167,7 @@ void createSCD_when_sclEditor_importSTDElementsInSCD_Fail_should_throw_exception doNothing().when(sclEditor).addHistoryItem(any(SCL.class), any(), any(), any()); doNothing().when(substationEditor).addSubstation(any(SCL.class), any(SCL.class)); doThrow(new ScdException("importSTDElementsInSCD fail")) - .when(sclEditor).importSTDElementsInSCD(any(SCL.class), anyList(), anyList()); + .when(sclEditor).importSTDElementsInSCD(any(SCL.class), anyList()); // When Then assertThatThrownBy(() -> sclAutomationService.createSCD(ssd, headerDTO, List.of(std))) .isInstanceOf(ScdException.class) @@ -183,7 +183,7 @@ void createSCD_when_controlBlockEditor_removeAllControlBlocksAndDatasetsAndExtRe when(sclEditor.initScl(any(UUID.class), anyString(), anyString())).thenReturn((SCL) BeanUtils.cloneBean(scl)); doNothing().when(sclEditor).addHistoryItem(any(SCL.class), any(), any(), any()); doNothing().when(substationEditor).addSubstation(any(SCL.class), any(SCL.class)); - doNothing().when(sclEditor).importSTDElementsInSCD(any(SCL.class), anyList(), anyList()); + doNothing().when(sclEditor).importSTDElementsInSCD(any(SCL.class), anyList()); doThrow(new ScdException("removeAllControlBlocksAndDatasetsAndExtRefSrcBindings fail")) .when(controlBlockEditor).removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(any(SCL.class)); // When Then diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/SclService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/SclService.java index 9019c8dbe..d08493c57 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/SclService.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/SclService.java @@ -103,6 +103,58 @@ public void addSubnetworks(SCL scd, List subNetworks, SCL icd) th } } + @Override + public void addSubnetworks(SCL scd, SCL std, String iedName) throws ScdException { + Optional.ofNullable(std.getCommunication()).ifPresent(tCommunication -> + tCommunication.getSubNetwork().forEach(stdSubNetwork -> + stdSubNetwork.getConnectedAP().forEach(stdConnectedAP -> { + // verify if exist SCD/IED/ConnectedAP/apName equal to STD/Communication/SubNetwork/ConnectedAP/apName + if (scd.getIED().stream().filter(ied -> Objects.equals(ied.getName(), iedName)) + .flatMap(tied -> tied.getAccessPoint().stream()) + .noneMatch(tAccessPoint -> tAccessPoint.getName().equals(stdConnectedAP.getApName()))) { + throw new ScdException("Unknown AccessPoint :" + stdConnectedAP.getApName() + " in IED :" + iedName); + } + // add SubNetwork if not exist + if(scd.getCommunication() == null) { + scd.setCommunication(new TCommunication()); + } + TSubNetwork tSubNetwork = scd.getCommunication().getSubNetwork() + .stream() + .filter(subNetwork -> subNetwork.getName().equals(stdSubNetwork.getName())) + .findFirst() + .orElseGet(() -> { + TSubNetwork newSubNetwork = new TSubNetwork(); + newSubNetwork.setName(stdSubNetwork.getName()); + newSubNetwork.setType(stdSubNetwork.getType()); + scd.getCommunication().getSubNetwork().add(newSubNetwork); + return newSubNetwork; + }); + // add ConnectedAP to SubNetwork if not exist + String apName = stdConnectedAP.getApName(); + TConnectedAP tConnectedAP = tSubNetwork.getConnectedAP().stream() + .filter(connectedAP -> Objects.equals(connectedAP.getIedName(), iedName) + && Objects.equals(connectedAP.getApName(), apName)) + .findFirst() + .orElseGet(() -> { + TConnectedAP newConnectedAP = new TConnectedAP(); + newConnectedAP.setIedName(iedName); + newConnectedAP.setApName(apName); + tSubNetwork.getConnectedAP().add(newConnectedAP); + return newConnectedAP; + }); + //copy Address And PhysConn From Icd to Scd + std.getCommunication().getSubNetwork().stream() + .flatMap(subNetwork -> subNetwork.getConnectedAP().stream()) + .filter(connectedAP -> connectedAP.getApName().equals(tConnectedAP.getApName())) + .findFirst() + .ifPresent(connectedAP -> { + Optional.ofNullable(connectedAP.getAddress()).ifPresent(tConnectedAP::setAddress); + tConnectedAP.getPhysConn().addAll(connectedAP.getPhysConn()); + }); + })) + ); + } + @Override public void updateDAI(SCL scd, String iedName, String ldInst, DataAttributeRef dataAttributeRef) throws ScdException { long startTime = System.nanoTime(); @@ -139,7 +191,7 @@ public void updateDAI(SCL scd, String iedName, String ldInst, DataAttributeRef d } @Override - public void importSTDElementsInSCD(SCL scd, List stds, List subNetworkTypes) throws ScdException { + public void importSTDElementsInSCD(SCL scd, List stds) throws ScdException { //Check SCD and STD compatibilities Map mapICDSystemVersionUuidAndSTDFile = PrivateUtils.createMapICDSystemVersionUuidAndSTDFile(stds); @@ -167,9 +219,7 @@ public void importSTDElementsInSCD(SCL scd, List stds, List subNetworkDTOSet = SubNetworkDTO.createDefaultSubnetwork(iedName, communication, subNetworkTypes); - addSubnetworks(scdRootAdapter.getCurrentElem(), subNetworkDTOSet, std); + addSubnetworks(scdRootAdapter.getCurrentElem(), std, iedName); } }); } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/SclEditor.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/SclEditor.java index 9055372be..1040f0ea0 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/SclEditor.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/SclEditor.java @@ -90,6 +90,14 @@ public interface SclEditor { */ void addSubnetworks(SCL scd, List subNetworks, SCL icd) throws ScdException; + /** + * Add or update SubNetworks in SCL file from ICD file and rename ConnectedAP/@iedName + * @param scd SCL file in which SubNetworks should be added + * @param std STD file from which SubNetworks functional data are copied from + * @param stdIedName Ied Name + */ + void addSubnetworks(SCL scd, SCL std, String stdIedName) throws ScdException; + /** * Updates DAI based on given data in dataAttributeRef * @@ -118,7 +126,6 @@ public interface SclEditor { * * @param scd SCL object in which content of STD files are imported * @param stds list of STD files contenting datas to import into SCD - * @param subNetworkTypes couple of Subnetwork name and possible corresponding ConnectedAP names * @throws ScdException throws when inconsistency between Substation of SCL content and gien STD files as : *
    *
  • ICD_SYSTEM_VERSION_UUID in IED/Private of STD is not present in COMPAS-ICDHeader in Substation/../LNode of SCL
  • @@ -128,7 +135,7 @@ public interface SclEditor { *
  • COMPAS_ICDHEADER in Substation/../LNode of SCL not found in IED/Private of STD
  • *
*/ - void importSTDElementsInSCD(SCL scd, List stds, List subNetworkTypes) throws ScdException; + void importSTDElementsInSCD(SCL scd, List stds) throws ScdException; /** * Activate used LDevice and Deactivate unused LDevice in {@link TLNode TLNode } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/SclServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/SclServiceTest.java index 3c28cdaed..5620f4414 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/SclServiceTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/SclServiceTest.java @@ -23,8 +23,6 @@ import org.lfenergy.compas.sct.commons.scl.ln.LNAdapter; import org.lfenergy.compas.sct.commons.testhelpers.MarshallerWrapper; import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; -import org.lfenergy.compas.sct.commons.scl.ied.*; -import org.lfenergy.compas.sct.commons.testhelpers.*; import org.mockito.InjectMocks; import org.mockito.junit.jupiter.MockitoExtension; @@ -174,6 +172,91 @@ void addSubnetworks_whenNoCommunicationTagInIcd_should_not_add_subnetwork() { assertThat(marshalledScd).doesNotContain(" sclService.addSubnetworks(scd, icd, "IED_NAME1")).doesNotThrowAnyException(); + String marshalledScd = assertIsMarshallable(scd); + assertThat(scd.getCommunication()).isNull(); + assertThat(marshalledScd).doesNotContain(" sclService.addSubnetworks(scd, std, "IED_NAME1")).doesNotThrowAnyException(); + assertThat(scd.getCommunication()).isNotNull(); + String marshalledScd = assertIsMarshallable(scd); + assertThat(marshalledScd).contains(" sclService.addSubnetworks(scd, std, "IED_NAME1")).doesNotThrowAnyException(); + assertThat(scd.getCommunication()).isNotNull(); + // assertion succeeds as subNetwork.connectedAP.iedName and subNetwork.connectedAP.gse fields are ignored. + // Only subNetwork.connectedAP.address and subNetwork.connectedAP.physConn added: see https://github.com/com-pas/compas-sct/issues/76 + assertThat(scd.getCommunication()) + .usingRecursiveComparison() + .ignoringFields("subNetwork.connectedAP.iedName", "subNetwork.connectedAP.gse") + .isEqualTo(std.getCommunication()); + assertIsMarshallable(scd); + } + + @Test + void addSubnetworks_shouldDoNothing_when_subNetworkAlreadyExist() { + //Givens + SCL scd = SclTestMarshaller.getSCLFromFile("/scl_update_communication/scd_without_communication.xml"); + SCL std = SclTestMarshaller.getSCLFromFile("/scl_update_communication/std_with_communication.xml"); + std.getCommunication().getSubNetwork().get(0).getConnectedAP().get(0).getPhysConn().clear(); + std.getCommunication().getSubNetwork().get(0).getConnectedAP().get(0).setAddress(null); + std.getCommunication().getSubNetwork().get(0).getConnectedAP().get(0).unsetGSE(); + //When + //Then + assertThatCode(() -> sclService.addSubnetworks(scd, std, "IED_NAME1")).doesNotThrowAnyException(); + String marshalledScd = assertIsMarshallable(scd); + assertThat(marshalledScd).contains(" sclService.addSubnetworks(scd, icd, "UnknownIedName")) + .isInstanceOf(ScdException.class) + .hasMessage("Unknown AccessPoint :ConnectedAP_Name in IED :UnknownIedName"); + assertIsMarshallable(scd); + } + @Test void testInitScl_With_headerId_shouldNotThrowError() { //Given @@ -240,7 +323,7 @@ void testImportSTDElementsInSCD_whenCalledWithOneSTD_shouldNotThrowException() { SCL scd = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/scd.xml"); SCL std = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/std.xml"); //When Then - assertThatCode(() -> sclService.importSTDElementsInSCD(scd, List.of(std), DTO.SUB_NETWORK_TYPES)) + assertThatCode(() -> sclService.importSTDElementsInSCD(scd, List.of(std))) .doesNotThrowAnyException(); assertThat(scd.getIED()).hasSize(1); assertThat(scd.getDataTypeTemplates()).hasNoNullFieldsOrProperties(); @@ -256,7 +339,7 @@ void importSTDElementsInSCD_whenCalledWithMultipleSTD_shouldNotThrowException() SCL std1 = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/std_SITESITE1SCU1.xml"); SCL std2 = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/std_SITESITE1SCU2.xml"); //When Then - assertThatCode(() -> sclService.importSTDElementsInSCD(scd, List.of(std0, std1, std2), DTO.SUB_NETWORK_TYPES)) + assertThatCode(() -> sclService.importSTDElementsInSCD(scd, List.of(std0, std1, std2))) .doesNotThrowAnyException(); assertThat(scd.getIED()).hasSize(3); assertThat(scd.getDataTypeTemplates()).hasNoNullFieldsOrProperties(); @@ -274,7 +357,7 @@ void importSTDElementsInSCD_whenManySTDMatchCompasICDHeader_shouldThrowException SCL std2 = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/std.xml"); List stds = List.of(std1, std2); //When Then - assertThatThrownBy(() -> sclService.importSTDElementsInSCD(scd, stds, DTO.SUB_NETWORK_TYPES)) + assertThatThrownBy(() -> sclService.importSTDElementsInSCD(scd, stds)) .isInstanceOf(ScdException.class); assertIsMarshallable(scd); } @@ -285,7 +368,7 @@ void importSTDElementsInSCD_whenSCDFileContainsSameICDHeaderInTwoDifferentFuncti SCL scd = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/scd_with_same_compas_icd_header_in_different_functions.xml"); SCL std = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/std.xml"); //When Then - assertThatCode(() -> sclService.importSTDElementsInSCD(scd, List.of(std), DTO.SUB_NETWORK_TYPES)).doesNotThrowAnyException(); + assertThatCode(() -> sclService.importSTDElementsInSCD(scd, List.of(std))).doesNotThrowAnyException(); assertIsMarshallable(scd); } @@ -296,7 +379,7 @@ void importSTDElementsInSCD_whenCompasICDHeaderNotMatch__shouldThrowException() SCL std = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/std_with_same_ICDSystemVersionUUID.xml"); List stdList = List.of(std); //When Then - assertThatThrownBy(() -> sclService.importSTDElementsInSCD(scd, stdList, DTO.SUB_NETWORK_TYPES)) + assertThatThrownBy(() -> sclService.importSTDElementsInSCD(scd, stdList)) .isInstanceOf(ScdException.class) .hasMessageContaining("COMPAS-ICDHeader is not the same in Substation and in IED"); assertIsMarshallable(scd); @@ -308,7 +391,7 @@ void importSTDElementsInSCD_whenNoSTDMatch_shouldThrowException() { SCL scd = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/ssd.xml"); List stdList = List.of(); //When Then - assertThatCode(() -> sclService.importSTDElementsInSCD(scd, stdList, DTO.SUB_NETWORK_TYPES)) + assertThatCode(() -> sclService.importSTDElementsInSCD(scd, stdList)) .isInstanceOf(ScdException.class) .hasMessage("There is no STD file found corresponding to headerId = f8dbc8c1-2db7-4652-a9d6-0b414bdeccfa, headerVersion = 01.00.00, headerRevision = 01.00.00 and ICDSystemVersionUUID = IED4d4fe1a8cda64cf88a5ee4176a1a0eef"); } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/DTO.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/DTO.java index 7193c0129..d9048bd2a 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/DTO.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/DTO.java @@ -7,7 +7,6 @@ import org.lfenergy.compas.scl2007b4.model.*; import java.time.LocalDateTime; -import java.util.List; import java.util.UUID; public class DTO { @@ -301,7 +300,4 @@ public static HeaderDTO.HistoryItem createHeaderItem(String now) { return historyItem; } - public static final List SUB_NETWORK_TYPES = List.of( - new SubNetworkTypeDTO("RSPACE_PROCESS_NETWORK", SubNetworkDTO.SubnetworkType.MMS.toString(), List.of("PROCESS_AP", "TOTO_AP_GE")), - new SubNetworkTypeDTO("RSPACE_ADMIN_NETWORK", SubNetworkDTO.SubnetworkType.MMS.toString(), List.of("ADMIN_AP", "TATA_AP_EFFACEC"))); } diff --git a/sct-commons/src/test/resources/scl_update_communication/scd_without_communication.xml b/sct-commons/src/test/resources/scl_update_communication/scd_without_communication.xml new file mode 100644 index 000000000..47e4425bb --- /dev/null +++ b/sct-commons/src/test/resources/scl_update_communication/scd_without_communication.xml @@ -0,0 +1,13 @@ + + + + + + + SCD + +
+ + + + \ No newline at end of file diff --git a/sct-commons/src/test/resources/scl_update_communication/std_with_communication.xml b/sct-commons/src/test/resources/scl_update_communication/std_with_communication.xml new file mode 100644 index 000000000..ee0d944e3 --- /dev/null +++ b/sct-commons/src/test/resources/scl_update_communication/std_with_communication.xml @@ -0,0 +1,18 @@ + + + + + + + STD + +
+ + + + + + + + + \ No newline at end of file diff --git a/sct-commons/src/test/resources/scl_update_communication/std_with_full_filled_communication.xml b/sct-commons/src/test/resources/scl_update_communication/std_with_full_filled_communication.xml new file mode 100644 index 000000000..710b4e786 --- /dev/null +++ b/sct-commons/src/test/resources/scl_update_communication/std_with_full_filled_communication.xml @@ -0,0 +1,30 @@ + + + + + + + STD + +
+ + + +
+

1.2.3.4

+
+ +
+

11

+
+
+ +

PL

+
+
+
+
+ + + + \ No newline at end of file diff --git a/sct-commons/src/test/resources/scl_update_communication/std_without_communication.xml b/sct-commons/src/test/resources/scl_update_communication/std_without_communication.xml new file mode 100644 index 000000000..475148733 --- /dev/null +++ b/sct-commons/src/test/resources/scl_update_communication/std_without_communication.xml @@ -0,0 +1,13 @@ + + + + + + + STD + +
+ + + + \ No newline at end of file