diff --git a/.github/workflows/release-project.yml b/.github/workflows/release-project.yml index 7656d1764..42c510cc2 100644 --- a/.github/workflows/release-project.yml +++ b/.github/workflows/release-project.yml @@ -6,7 +6,7 @@ name: Release Project on: release: - types: [ released ] + types: [ published ] jobs: publish: @@ -42,4 +42,4 @@ jobs: - name: Deploy with Maven to GitHub Packages run: mvn --batch-mode -s custom_maven_settings.xml clean deploy env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LDEPFSettings.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LDEPFSettings.java new file mode 100644 index 000000000..67ceec6c4 --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LDEPFSettings.java @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2023 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.dto; + +import java.util.List; + +/** + * Represents a list of LDEPF settings + * This is a functional interface whose functional method is getLDEPFSettings + * the type of the input to the operation + * + * @param the type of the result of the LDEPFSettings + * + * @see org.lfenergy.compas.sct.commons.util.SettingLDEPFCsvHelper + */ +@FunctionalInterface +public interface LDEPFSettings { + + /** + * This method provides list of LDEPF settings + */ + List getSettings(); +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplate.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplate.java index 966bfa367..f16c6dc2d 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplate.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplate.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.*; import org.lfenergy.compas.scl2007b4.model.*; +import org.lfenergy.compas.sct.commons.scl.ied.AbstractLNAdapter; import org.lfenergy.compas.sct.commons.util.SclConstructorHelper; import java.util.ArrayList; @@ -50,12 +51,25 @@ public class ResumedDataTemplate { @NonNull private DaTypeName daName = new DaTypeName(""); + /** + * Constructor + */ + public ResumedDataTemplate(AbstractLNAdapter lnAdapter, String doName, String daName) { + this.lnClass = lnAdapter.getLNClass(); + this.lnInst = lnAdapter.getLNInst(); + this.prefix = lnAdapter.getPrefix(); + this.lnType = lnAdapter.getLnType(); + this.doName = new DoTypeName(doName); + this.daName = new DaTypeName(daName); + } + /** * Copies summarized DataTypeTemplate information to another one + * * @param dtt input * @return Updated ResumedDataTemplate object */ - public static ResumedDataTemplate copyFrom(ResumedDataTemplate dtt){ + public static ResumedDataTemplate copyFrom(ResumedDataTemplate dtt) { ResumedDataTemplate resumedDataTemplate = new ResumedDataTemplate(); resumedDataTemplate.prefix = dtt.prefix; resumedDataTemplate.lnClass = dtt.lnClass; diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ExtRefService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ExtRefService.java index 8eca30a31..e1f54c278 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ExtRefService.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ExtRefService.java @@ -8,6 +8,7 @@ import org.apache.commons.lang3.StringUtils; import org.lfenergy.compas.scl2007b4.model.SCL; import org.lfenergy.compas.scl2007b4.model.TCompasICDHeader; +import org.lfenergy.compas.scl2007b4.model.TExtRef; import org.lfenergy.compas.scl2007b4.model.TIED; import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings; import org.lfenergy.compas.sct.commons.dto.SclReport; @@ -27,6 +28,7 @@ import java.util.stream.Stream; import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.*; +import static org.lfenergy.compas.sct.commons.util.Utils.isExtRefFeedBySameControlBlock; @UtilityClass public class ExtRefService { @@ -226,4 +228,19 @@ private static Optional configureControlBlockNetwork(ControlBlock return controlBlockAdapter.configureNetwork(appIdIterator.nextLong(), macAddressIterator.next(), settings.vlanId(), settings.vlanPriority(), settings.minTime(), settings.maxTime()); } + + + /** + * Remove ExtRef which are fed by same Control Block + * + * @return list ExtRefs without duplication + */ + public static List filterDuplicatedExtRefs(List tExtRefs) { + List filteredList = new ArrayList<>(); + tExtRefs.forEach(tExtRef -> { + if (filteredList.stream().noneMatch(t -> isExtRefFeedBySameControlBlock(tExtRef, t))) + filteredList.add(tExtRef); + }); + return filteredList; + } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclService.java index cca4964ad..506bbb55c 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclService.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclService.java @@ -80,6 +80,7 @@ public class SclService { private static final String UNKNOWN_LDEVICE_S_IN_IED_S = "Unknown LDevice (%s) in IED (%s)"; private static final String INVALID_OR_MISSING_ATTRIBUTES_IN_EXT_REF_BINDING_INFO = "Invalid or missing attributes in ExtRef binding info"; + private static final String IED_TEST_NAME = "IEDTEST"; private SclService() { throw new IllegalStateException("SclService class"); @@ -609,4 +610,20 @@ public static SclReport updateDoInRef(SCL scd) { .toList(); return new SclReport(sclRootAdapter, sclReportItems); } + + /** + * Update and/or create Monitoring LNs (LSVS and LGOS) for bound GOOSE and SMV Control Blocks + * + * @param scd SCL file for which LNs (LSVS and LGOS) should be updated and/or created in each LDevice LDSUIED with matching ExtRef information + * @return SclReport Object that contain SCL file and set of errors + */ + public static SclReport manageMonitoringLns(SCL scd) { + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + List sclReportItems = sclRootAdapter.streamIEDAdapters() + .filter(iedAdapter -> !iedAdapter.getName().contains(IED_TEST_NAME)) + .map(IEDAdapter::manageMonitoringLns) + .flatMap(List::stream) + .toList(); + return new SclReport(sclRootAdapter, sclReportItems); + } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AccessPointAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AccessPointAdapter.java index a0fb6bacc..6b00ec4d8 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AccessPointAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AccessPointAdapter.java @@ -17,6 +17,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.lfenergy.compas.sct.commons.scl.ExtRefService.filterDuplicatedExtRefs; + /** * A representation of the model object * {@link org.lfenergy.compas.scl2007b4.model.TAccessPoint AccessPoint}. @@ -35,7 +37,6 @@ public class AccessPointAdapter extends SclElementAdapter { public static final long MAX_OCCURRENCE_NO_LIMIT_VALUE = -1L; - private static final String CLIENT_IED_NAME = "The Client IED "; /** * Constructor @@ -219,7 +220,7 @@ public Optional checkLimitationForBoundIedFcdas(List tEx * @param sclReportItems * @param tExtRefs */ - record ExtRefAnalyzeRecord(List sclReportItems, List tExtRefs) { + public record ExtRefAnalyzeRecord(List sclReportItems, List tExtRefs) { } /** @@ -229,21 +230,20 @@ record ExtRefAnalyzeRecord(List sclReportItems, List tEx */ public ExtRefAnalyzeRecord getAllCoherentExtRefForAnalyze() { List sclReportItems = new ArrayList<>(); - List tExtRefList = new ArrayList<>(); - streamLDeviceAdapters().map(lDeviceAdapter -> { - List extRefs = lDeviceAdapter.getLN0Adapter().getExtRefs().stream().filter(TExtRef::isSetSrcCBName).collect(Collectors.toCollection(ArrayList::new)); - sclReportItems.addAll(checkExtRefWithoutServiceType(extRefs, lDeviceAdapter.getLN0Adapter().getXPath())); - extRefs.removeIf(tExtRef -> !tExtRef.isSetServiceType()); - return extRefs; - }).flatMap(Collection::stream).forEach(tExtRef -> { - if (tExtRefList.isEmpty()) - tExtRefList.add(tExtRef); - else { - if (tExtRefList.stream().noneMatch(t -> isExtRefFeedBySameControlBlock(tExtRef, t))) - tExtRefList.add(tExtRef); - } - }); - return new ExtRefAnalyzeRecord(sclReportItems, tExtRefList); + List tExtRefList = streamLDeviceAdapters() + .map(LDeviceAdapter::getLN0Adapter) + .map(ln0Adapter -> { + List extRefs = new ArrayList<>(); + if (ln0Adapter.hasInputs()) { + extRefs.addAll(ln0Adapter.getInputsAdapter().filterDuplicatedExtRefs() + .stream().filter(TExtRef::isSetSrcCBName).collect(Collectors.toCollection(ArrayList::new))); + sclReportItems.addAll(checkExtRefWithoutServiceType(extRefs, ln0Adapter.getXPath())); + extRefs.removeIf(tExtRef -> !tExtRef.isSetServiceType()); + } + return extRefs; + }).flatMap(Collection::stream) + .toList(); + return new ExtRefAnalyzeRecord(sclReportItems, filterDuplicatedExtRefs(tExtRefList)); } /** @@ -262,25 +262,6 @@ private List checkExtRefWithoutServiceType(List tExtRefs .toList(); } - /** - * Checks if two ExtRefs fed by same Control Block for SCL limits analyze - * Nota : this equality is only for checking limitation check - * - * @param t1 extref to compare - * @param t2 extref to compare - * @return true if the two ExtRef are fed by same Control Block, otherwise false - */ - private static boolean isExtRefFeedBySameControlBlock(TExtRef t1, TExtRef t2) { - String srcLNClass1 = (t1.isSetSrcLNClass()) ? t1.getSrcLNClass().get(0) : TLLN0Enum.LLN_0.value(); - String srcLNClass2 = (t2.isSetSrcLNClass()) ? t2.getSrcLNClass().get(0) : TLLN0Enum.LLN_0.value(); - return Utils.equalsOrBothBlank(t1.getIedName(), t2.getIedName()) - && Utils.equalsOrBothBlank(t1.getSrcLDInst(), t2.getSrcLDInst()) - && srcLNClass1.equals(srcLNClass2) - && Utils.equalsOrBothBlank(t1.getSrcLNInst(), t2.getSrcLNInst()) - && Utils.equalsOrBothBlank(t1.getSrcPrefix(), t2.getSrcPrefix()) - && t1.getServiceType().equals(t2.getServiceType()); - } - /** * Checks Control Blocks (Report, Goose, SMV) number limitation for bound IED * @@ -300,7 +281,6 @@ public List checkLimitationForBoundIEDControls(List tExt * Checks Control Block number limitation for bound IED * * @param tExtRefs list of ExtRefs referenced same ied - * @param msg message to display hen error occured * @param servicesConfigEnum type of Control Block for which check is done * @return Optional of encountered error or empty */ diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java index 451e8d6a5..b48255600 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java @@ -6,6 +6,7 @@ import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.dto.ExtrefTarget; +import org.lfenergy.compas.sct.commons.dto.ResumedDataTemplate; import org.lfenergy.compas.sct.commons.dto.SclReportItem; import org.lfenergy.compas.sct.commons.scl.ObjectReference; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; @@ -109,36 +110,45 @@ public AbstractDAIAdapter toAdapter(TDAI childTDAI) { * @return a filled SclReportItem if an error occurs, empty SclReportItem otherwise */ public Optional updateDaiFromExtRef(List tExtRefs) { + Optional optionalSclReportItem; Optional tExtRefMinOptional = tExtRefs.stream().min(EXTREF_DESC_SUFFIX_COMPARATOR); - if (tExtRefMinOptional.isPresent() && extractDescSuffix(tExtRefMinOptional.get().getDesc()) == 1) { TExtRef tExtRefMin = tExtRefMinOptional.get(); - findDataAdapterByName(DA_NAME_SET_SRC_REF) - .orElse(addDAI(DA_NAME_SET_SRC_REF, true)) - .setVal(createInRefValNominalString(tExtRefMin)); + String valueSrcRef = createInRefValNominalString(tExtRefMin); + optionalSclReportItem = updateDAI(DA_NAME_SET_SRC_REF, valueSrcRef); if (tExtRefMin.isSetSrcCBName()) { - findDataAdapterByName(DA_NAME_SET_SRC_CB) - .orElse(addDAI(DA_NAME_SET_SRC_CB, true)) - .setVal(createInRefValTestString(tExtRefMin)); + String valueSrcCb = createInRefValTestString(tExtRefMin); + optionalSclReportItem = updateDAI(DA_NAME_SET_SRC_CB, valueSrcCb); } Optional tExtRefMaxOptional = tExtRefs.stream().max(EXTREF_DESC_SUFFIX_COMPARATOR); if (tExtRefMaxOptional.isPresent() && extractDescSuffix(tExtRefMaxOptional.get().getDesc()) > 1) { TExtRef tExtRefMax = tExtRefMaxOptional.get(); - findDataAdapterByName(DA_NAME_SET_TST_REF) - .orElse(addDAI(DA_NAME_SET_TST_REF, true)) - .setVal(createInRefValNominalString(tExtRefMax)); + String valueTstRef = createInRefValNominalString(tExtRefMax); + optionalSclReportItem = updateDAI(DA_NAME_SET_TST_REF, valueTstRef); if (tExtRefMax.isSetSrcCBName()) { - findDataAdapterByName(DA_NAME_SET_TST_CB) - .orElse(addDAI(DA_NAME_SET_TST_CB, true)) - .setVal(createInRefValTestString(tExtRefMax)); + String valueTstCb = createInRefValTestString(tExtRefMax); + optionalSclReportItem = updateDAI(DA_NAME_SET_TST_CB, valueTstCb); } } } else { - return Optional.of(SclReportItem.warning(getXPath(), "The DOI %s can't be bound with an ExtRef".formatted(getXPath()))); + optionalSclReportItem = Optional.of(SclReportItem.warning(getXPath(), "The DOI %s can't be bound with an ExtRef".formatted(getXPath()))); } + return optionalSclReportItem; + } + + private Optional updateDAI(String daName, String value) { + ResumedDataTemplate daiFilterSrcRef = new ResumedDataTemplate(getParentAdapter(), getName(), daName); + Optional foundDais = getParentAdapter().getDAI(daiFilterSrcRef, true).stream().findFirst(); + if (foundDais.isEmpty()) { + return Optional.of(SclReportItem.warning(getXPath() + "/DAI@name=\"" + daName + "\"/Val", "The DAI cannot be updated")); + } + ResumedDataTemplate filterForUpdate = foundDais.get(); + filterForUpdate.setVal(value); + getParentAdapter().updateDAI(filterForUpdate); return Optional.empty(); + } private static int extractDescSuffix(String desc) throws NumberFormatException { diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapter.java index e24f8da89..7fa193582 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapter.java @@ -15,13 +15,11 @@ import org.lfenergy.compas.sct.commons.scl.PrivateService; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; +import org.lfenergy.compas.sct.commons.util.MonitoringLnClassEnum; import org.lfenergy.compas.sct.commons.util.ServicesConfigEnum; import org.lfenergy.compas.sct.commons.util.Utils; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import java.util.function.Function; import java.util.stream.Stream; @@ -62,6 +60,9 @@ public class IEDAdapter extends SclElementAdapter { private static final String MESSAGE_LDEVICE_INST_NOT_FOUND = "LDevice.inst '%s' not found in IED '%s'"; + private static final String DO_GOCBREF = "GoCBRef"; + private static final String DO_SVCBREF = "SvCBRef"; + private static final String LDSUIED_LDINST = "LDSUIED"; /** * Constructor @@ -91,10 +92,10 @@ public IEDAdapter(SclRootAdapter parentAdapter, TIED currentElem) { public IEDAdapter(SclRootAdapter parentAdapter, String iedName) throws ScdException { super(parentAdapter); TIED ied = parentAdapter.getCurrentElem().getIED() - .stream() - .filter(tied -> tied.getName().equals(iedName)) - .findFirst() - .orElseThrow(() -> new ScdException("Unknown IED name :" + iedName)); + .stream() + .filter(tied -> tied.getName().equals(iedName)) + .findFirst() + .orElseThrow(() -> new ScdException("Unknown IED name :" + iedName)); setCurrentElem(ied); } @@ -326,19 +327,20 @@ public Optional getPrivateCompasBay() { /** * Checks if Controls, DataSets and FCDAs of IED respect config limitation + * * @return empty list if all IED respect limits, otherwise list of errors */ public List checkDataGroupCoherence() { return streamAccessPointAdapters() .flatMap(accessPointAdapter -> Stream.concat( - accessPointAdapter.checkFCDALimitations().stream(), - Stream.of( - accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.DATASET), - accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.REPORT), - accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.GSE), - accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.SMV)) - .flatMap(Optional::stream) + accessPointAdapter.checkFCDALimitations().stream(), + Stream.of( + accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.DATASET), + accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.REPORT), + accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.GSE), + accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.SMV)) + .flatMap(Optional::stream) ) ) .toList(); @@ -346,27 +348,29 @@ public List checkDataGroupCoherence() { /** * Checks if Controls and FCDAs of source IEDs respect config limitation + * * @return empty list if all IED respect limits, otherwise list of errors */ public List checkBindingDataGroupCoherence() { - return streamAccessPointAdapters() + return streamAccessPointAdapters() .flatMap(accessPointAdapter -> { AccessPointAdapter.ExtRefAnalyzeRecord extRefAnalyzeRecord = accessPointAdapter.getAllCoherentExtRefForAnalyze(); return Stream.of( - extRefAnalyzeRecord.sclReportItems().stream(), - accessPointAdapter.checkLimitationForBoundIedFcdas(extRefAnalyzeRecord.tExtRefs()).stream(), - accessPointAdapter.checkLimitationForBoundIEDControls(extRefAnalyzeRecord.tExtRefs()).stream()) - .flatMap(Function.identity()); + extRefAnalyzeRecord.sclReportItems().stream(), + accessPointAdapter.checkLimitationForBoundIedFcdas(extRefAnalyzeRecord.tExtRefs()).stream(), + accessPointAdapter.checkLimitationForBoundIEDControls(extRefAnalyzeRecord.tExtRefs()).stream()) + .flatMap(Function.identity()); }).toList(); } private Stream streamAccessPointAdapters() { return currentElem.getAccessPoint().stream() - .map(tAccessPoint -> new AccessPointAdapter(this, tAccessPoint)); + .map(tAccessPoint -> new AccessPointAdapter(this, tAccessPoint)); } /** * Get value of private type COMPAS-ICDHeader + * * @return COMPAS-ICDHeader private value if present, else empty Optional */ public Optional getCompasICDHeader() { @@ -375,10 +379,40 @@ public Optional getCompasICDHeader() { /** * Get value of private type COMPAS-SystemVersion + * * @return COMPAS-SystemVersion private value if present, else empty Optional */ public Optional getCompasSystemVersion() { return PrivateService.extractCompasPrivate(currentElem, TCompasSystemVersion.class); } + /** + * Update and/or create Monitoring LNs (LSVS and LGOS) into LDSUIED for each bound ExtRef of each LDevice + * + * @return a list of SclReport Objects that contains errors + */ + public List manageMonitoringLns() { + List sclReportItems = new ArrayList<>(); + findLDeviceAdapterByLdInst(LDSUIED_LDINST).ifPresent(lDeviceAdapter -> { + lDeviceAdapter.manageMonitoringLns(retrieveAllExtRefForServiceType(TServiceType.GOOSE), DO_GOCBREF, MonitoringLnClassEnum.LGOS) + .ifPresent(sclReportItems::add); + lDeviceAdapter.manageMonitoringLns(retrieveAllExtRefForServiceType(TServiceType.SMV), DO_SVCBREF, MonitoringLnClassEnum.LSVS) + .ifPresent(sclReportItems::add); + }); + return sclReportItems; + } + + private List retrieveAllExtRefForServiceType(TServiceType tServiceType) { + return streamLDeviceAdapters() + .map(LDeviceAdapter::getLN0Adapter) + .filter(AbstractLNAdapter::hasInputs) + .map(LN0Adapter::getInputsAdapter) + .map(InputsAdapter::filterDuplicatedExtRefs) + .flatMap(List::stream) + .filter(tExtRef -> tExtRef.isSetServiceType() && tExtRef.isSetSrcCBName() && + tServiceType.equals(tExtRef.getServiceType())) + .toList(); + } + + } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapter.java index 0f0496fc1..eebde2652 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapter.java @@ -11,6 +11,7 @@ import org.lfenergy.compas.sct.commons.dto.ResumedDataTemplate; import org.lfenergy.compas.sct.commons.dto.SclReportItem; import org.lfenergy.compas.sct.commons.exception.ScdException; +import org.lfenergy.compas.sct.commons.scl.ExtRefService; import org.lfenergy.compas.sct.commons.scl.PrivateService; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; @@ -421,4 +422,13 @@ private SclRootAdapter getSclRootAdapter() { return getIedAdapter().getParentAdapter(); } + /** + * Remove ExtRef which are fed by same Control Block + * + * @return list ExtRefs without duplication + */ + public List filterDuplicatedExtRefs() { + return ExtRefService.filterDuplicatedExtRefs(getExtRefs()); + } + } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java index 50cbcbb22..cacde73a2 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java @@ -13,10 +13,13 @@ import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import org.lfenergy.compas.sct.commons.scl.dtt.DataTypeTemplateAdapter; import org.lfenergy.compas.sct.commons.util.ControlBlockEnum; +import org.lfenergy.compas.sct.commons.util.MonitoringLnClassEnum; import org.lfenergy.compas.sct.commons.util.Utils; import java.util.*; +import static org.lfenergy.compas.sct.commons.util.Utils.copySclElement; + /** * A representation of the model object * {@link org.lfenergy.compas.scl2007b4.model.TLDevice LDevice}. @@ -50,10 +53,13 @@ @Slf4j public class LDeviceAdapter extends SclElementAdapter { + private static final String DA_SETSRCREF = "setSrcRef"; + /** * Constructor + * * @param parentAdapter Parent container reference - * @param currentElem Current reference + * @param currentElem Current reference */ public LDeviceAdapter(IEDAdapter parentAdapter, TLDevice currentElem) { super(parentAdapter, currentElem); @@ -61,6 +67,7 @@ public LDeviceAdapter(IEDAdapter parentAdapter, TLDevice currentElem) { /** * Check if node is child of the reference node + * * @return link parent child existence */ @Override @@ -75,21 +82,21 @@ protected boolean amChildElementRef() { .anyMatch(tlDevice -> currentElem.getInst().equals(tlDevice.getInst())); } - public TAccessPoint getAccessPoint(){ + public TAccessPoint getAccessPoint() { return parentAdapter.getCurrentElem().getAccessPoint() - .stream() - .filter(accessPoint -> - Optional.ofNullable(accessPoint.getServer()) - .filter(TServer::isSetLDevice) - .map(TServer::getLDevice) - .stream() - .flatMap(List::stream) - .map(TLDevice::getInst) - .anyMatch(inst -> inst.equals(currentElem.getInst())) - ) - .findFirst() - .orElseThrow(() -> new IllegalStateException(String.format("LDevice.inst='%s' not found in parent IED.name='%s'", currentElem.getInst(), - parentAdapter.getName()))); + .stream() + .filter(accessPoint -> + Optional.ofNullable(accessPoint.getServer()) + .filter(TServer::isSetLDevice) + .map(TServer::getLDevice) + .stream() + .flatMap(List::stream) + .map(TLDevice::getInst) + .anyMatch(inst -> inst.equals(currentElem.getInst())) + ) + .findFirst() + .orElseThrow(() -> new IllegalStateException(String.format("LDevice.inst='%s' not found in parent IED.name='%s'", currentElem.getInst(), + parentAdapter.getName()))); } @Override @@ -99,7 +106,7 @@ protected String elementXPath() { @Override public String getXPath() { - if (parentAdapter != null){ + if (parentAdapter != null) { return parentAdapter.getXPath() + "/AccessPoint/Server/" + elementXPath(); } else { return super.getXPath(); @@ -108,11 +115,12 @@ public String getXPath() { /** * Updates LDevice name by combining IED name and LDevice ldInst value + * * @throws ScdException throws when renaming LDevice and new name has more than 33 caracteres */ public void updateLDName() throws ScdException { String newLdName = parentAdapter.getCurrentElem().getName() + currentElem.getInst(); - if(newLdName.length() > 33){ + if (newLdName.length() > 33) { throw new ScdException(newLdName + "(IED.name + LDevice.inst) has more than 33 characters"); } // renaming ldName @@ -121,14 +129,16 @@ public void updateLDName() throws ScdException { /** * Gets current LDevice Inst parameter value + * * @return Inst parameter value */ - public String getInst(){ + public String getInst() { return currentElem.getInst(); } /** * Gets current LDevice name + * * @return LDevice name */ public String getLdName() { @@ -137,75 +147,81 @@ public String getLdName() { /** * Gets current LDevice LNode LN0 + * * @return LN0Adapter */ - public LN0Adapter getLN0Adapter(){ + public LN0Adapter getLN0Adapter() { return new LN0Adapter(this, currentElem.getLN0()); } /** * Checks if LDevice has an LN0 node + * * @return true if lDevice has a LN0 node, false otherwise */ - public boolean hasLN0(){ + public boolean hasLN0() { return currentElem.isSetLN0(); } /** * Gets current LDevice LNodes (except LN0) + * * @return list of LNAdapter object */ - public List getLNAdapters(){ + public List getLNAdapters() { return currentElem.getLN() .stream() - .map(tln -> new LNAdapter(this,tln)) + .map(tln -> new LNAdapter(this, tln)) .toList(); } /** * Gets specific LNode from current LDevice + * * @param lnClass LNode lnClass value - * @param lnInst LNode lnInst value - * @param prefix LNode prefix value + * @param lnInst LNode lnInst value + * @param prefix LNode prefix value * @return LNAdapter object * @throws ScdException thros when specified LNode not found in current IED */ public LNAdapter getLNAdapter(String lnClass, String lnInst, String prefix) throws ScdException { return findLnAdapter(lnClass, lnInst, prefix) .orElseThrow( - ()-> new ScdException( - String.format( - "LDevice [%s] has no LN [%s,%s,%s]", currentElem.getInst(),lnClass,lnInst,prefix) - ) - ); + () -> new ScdException( + String.format( + "LDevice [%s] has no LN [%s,%s,%s]", currentElem.getInst(), lnClass, lnInst, prefix) + ) + ); } /** * Find a specific LN from current LDevice + * * @param lnClass LNode lnClass value - * @param lnInst LNode lnInst value - * @param prefix LNode prefix value + * @param lnInst LNode lnInst value + * @param prefix LNode prefix value * @return LNAdapter object * @throws ScdException thros when specified LNode not found in current IED */ public Optional findLnAdapter(String lnClass, String lnInst, String prefix) { - if (!currentElem.isSetLN()){ + if (!currentElem.isSetLN()) { return Optional.empty(); } return currentElem.getLN() - .stream() - .filter(tln -> Utils.lnClassEquals(tln.getLnClass(), lnClass) - && tln.getInst().equals(lnInst) - && Utils.equalsOrBothBlank(prefix, tln.getPrefix())) - .map(tln -> new LNAdapter(this, tln)) - .findFirst(); + .stream() + .filter(tln -> Utils.lnClassEquals(tln.getLnClass(), lnClass) + && tln.getInst().equals(lnInst) + && Utils.equalsOrBothBlank(prefix, tln.getPrefix())) + .map(tln -> new LNAdapter(this, tln)) + .findFirst(); } /** * Checks all possible ExtRef in current LDevice which could be bound to given ExtRef as parameter + * * @param signalInfo ExtRef to bind data - * @return list of ExtRefBindingInfo object (containing binding data for each LDNode in current LDevice + * @return list of ExtRefBindingInfo object (containing binding data for each LDNode in current LDevice * related to given ExtRef) */ public List getExtRefBinders(ExtRefSignalInfo signalInfo) { @@ -214,7 +230,7 @@ public List getExtRefBinders(ExtRefSignalInfo signalInfo) { .filter(abstractLNAdapter -> StringUtils.isBlank(signalInfo.getPLN()) || abstractLNAdapter.getLNClass().equals(signalInfo.getPLN())) .map(lnAdapter -> { String lnType = lnAdapter.getLnType(); - ExtRefBindingInfo extRefBindingInfo = dttAdapter.getBinderResumedDTT(lnType,signalInfo); + ExtRefBindingInfo extRefBindingInfo = dttAdapter.getBinderResumedDTT(lnType, signalInfo); extRefBindingInfo.setIedName(parentAdapter.getName()); extRefBindingInfo.setLdInst(currentElem.getInst()); extRefBindingInfo.setLnClass(lnAdapter.getLNClass()); @@ -227,6 +243,7 @@ public List getExtRefBinders(ExtRefSignalInfo signalInfo) { /** * Gets all ExtRef of all LNodes of current LDevice + * * @return list of ExtRefInfo object (containing binding data for each LDNode in current LDevice) */ public List getExtRefInfo() { @@ -234,8 +251,8 @@ public List getExtRefInfo() { List> lnAdapters = getLNAdaptersIncludingLN0(); LogicalNodeOptions logicalNodeOptions = new LogicalNodeOptions(); logicalNodeOptions.setWithExtRef(true); - for(AbstractLNAdapter lnAdapter : lnAdapters) { - LNodeDTO lNodeDTO = LNodeDTO.from(lnAdapter,logicalNodeOptions); + for (AbstractLNAdapter lnAdapter : lnAdapters) { + LNodeDTO lNodeDTO = LNodeDTO.from(lnAdapter, logicalNodeOptions); extRefInfos.addAll(lNodeDTO.getExtRefs()); } return extRefInfos; @@ -243,23 +260,24 @@ public List getExtRefInfo() { /** * Gets a list of summarized DataTypeTemplate for DataAttribute DAIs (updatableOnly or not) - * @param rDtt reference resumed DataTypeTemplate (used as filter) + * + * @param rDtt reference resumed DataTypeTemplate (used as filter) * @param updatableOnly true to retrieve only updatableOnly DAIs, false to retrieve all DAIs * @return Set of ResumedDataTemplate (updatableOnly or not) * @throws ScdException SCD illegal arguments exception */ public Set getDAI(ResumedDataTemplate rDtt, boolean updatableOnly) throws ScdException { List> lnAdapters; - if(StringUtils.isBlank(rDtt.getLnClass())){ + if (StringUtils.isBlank(rDtt.getLnClass())) { lnAdapters = getLNAdaptersIncludingLN0(); - } else if(rDtt.getLnClass().equals(TLLN0Enum.LLN_0.value())){ - lnAdapters = hasLN0() ? Collections.singletonList(getLN0Adapter()) : Collections.emptyList(); + } else if (rDtt.getLnClass().equals(TLLN0Enum.LLN_0.value())) { + lnAdapters = hasLN0() ? Collections.singletonList(getLN0Adapter()) : Collections.emptyList(); } else { - lnAdapters = findLnAdapter(rDtt.getLnClass(),rDtt.getLnInst(),rDtt.getPrefix()).stream().toList(); + lnAdapters = findLnAdapter(rDtt.getLnClass(), rDtt.getLnInst(), rDtt.getPrefix()).stream().toList(); } - Set resumedDataTemplateSet = new HashSet<>(); - for(AbstractLNAdapter lnAdapter : lnAdapters){ + Set resumedDataTemplateSet = new HashSet<>(); + for (AbstractLNAdapter lnAdapter : lnAdapters) { ResumedDataTemplate filter = ResumedDataTemplate.copyFrom(rDtt); filter.setLnClass(lnAdapter.getLNClass()); filter.setLnInst(lnAdapter.getLNInst()); @@ -272,7 +290,7 @@ public Set getDAI(ResumedDataTemplate rDtt, boolean updatab } public Optional getLDeviceStatus() { - if (!hasLN0()){ + if (!hasLN0()) { return Optional.empty(); } return getLN0Adapter().getLDeviceStatus(); @@ -280,6 +298,7 @@ public Optional getLDeviceStatus() { /** * Gets all LN of LDevice including LN0 + * * @return list of all LN of LDevice */ public List> getLNAdaptersIncludingLN0() { @@ -289,24 +308,24 @@ public List> getLNAdaptersIncludingLN0() { return aLNAdapters; } - public List createDataSetAndControlBlocks(){ + public List createDataSetAndControlBlocks() { LN0Adapter ln0Adapter = getLN0Adapter(); - if (!ln0Adapter.hasInputs()){ + if (!ln0Adapter.hasInputs()) { return Collections.emptyList(); } return ln0Adapter.getInputsAdapter() - .updateAllSourceDataSetsAndControlBlocks(); + .updateAllSourceDataSetsAndControlBlocks(); } public Set findSourceDA(TExtRef extRef) { String extRefLnClass = extRef.getLnClass().stream().findFirst().orElse(""); ResumedDataTemplate filter = ResumedDataTemplate.builder() - .lnClass(extRefLnClass) - .prefix(extRef.getPrefix()) - .lnInst(extRef.getLnInst()) - .doName(new DoTypeName(extRef.getDoName())) - .daName(new DaTypeName(extRef.getDaName())) - .build(); + .lnClass(extRefLnClass) + .prefix(extRef.getPrefix()) + .lnInst(extRef.getLnInst()) + .doName(new DoTypeName(extRef.getDoName())) + .daName(new DaTypeName(extRef.getDaName())) + .build(); return getDAI(filter, false); } @@ -333,7 +352,7 @@ protected boolean hasDataSetCreationCapability(ControlBlockEnum controlBlockEnum private boolean hasDatSetConfOrDyn(TServiceSettings tServiceSettings) { return tServiceSettings.isSetDatSet() - && (TServiceSettingsEnum.CONF.equals(tServiceSettings.getDatSet()) || TServiceSettingsEnum.DYN.equals(tServiceSettings.getDatSet())); + && (TServiceSettingsEnum.CONF.equals(tServiceSettings.getDatSet()) || TServiceSettingsEnum.DYN.equals(tServiceSettings.getDatSet())); } /** @@ -359,6 +378,64 @@ protected boolean hasControlBlockCreationCapability(ControlBlockEnum controlBloc private boolean hasCBNameConf(TServiceSettings tServiceSettings) { return tServiceSettings.isSetCbName() - && (TServiceSettingsNoDynEnum.CONF.equals(tServiceSettings.getCbName())); + && (TServiceSettingsNoDynEnum.CONF.equals(tServiceSettings.getCbName())); + } + + /** + * Update and/or create Monitoring LNs (LSVS and LGOS) into LDSUIED from ExtRefs binding + * + * @param tExtRefs ExtRefs for which source Control Blocks (Goose or SMV) should be monitored + * @param monitoringLnClassEnum LNClass value for LN to monitor + * @return a list of SclReport Objects that contains errors + */ + public Optional manageMonitoringLns(List tExtRefs, String doName, MonitoringLnClassEnum monitoringLnClassEnum) { + if (tExtRefs.isEmpty()) { + return Optional.empty(); + } + return getLNAdapters().stream().filter(lnAdapter -> monitoringLnClassEnum.value().equals(lnAdapter.getLNClass())) + .map(lnAdapter -> { + Optional optionalSclReportItem = Optional.empty(); + ResumedDataTemplate filter = new ResumedDataTemplate(lnAdapter, doName, DA_SETSRCREF); + Optional foundDai = lnAdapter.getDAI(filter, true).stream().findFirst(); + if (foundDai.isEmpty()) { + optionalSclReportItem = Optional.of(SclReportItem.warning(lnAdapter.getXPath() + "/DOI@name=\"" + doName + "\"/DAI@name=\"setSrcRef\"/Val", + "The DAI cannot be updated")); + } else { + ResumedDataTemplate daToUpdateFilter = foundDai.get(); + TLN lnToUpdate = lnAdapter.getCurrentElem(); + removeLnsByLnClass(monitoringLnClassEnum); + for (int i = 0; i < tExtRefs.size(); i++) { + getCurrentElem().getLN().add(lnToUpdate); + updateNewCreatedLnDaiValue(lnToUpdate, tExtRefs.get(i), String.valueOf(i + 1), daToUpdateFilter); + lnToUpdate = copySclElement(lnAdapter.getCurrentElem(), TLN.class); //value copy + } + } + return optionalSclReportItem; + }).findFirst() + .orElse(Optional.of(SclReportItem.warning(getXPath(), "There is no LN %s present in LDevice".formatted(monitoringLnClassEnum.value())))); } + + private void removeLnsByLnClass(MonitoringLnClassEnum monitoringLnClassEnum) { + List lnToKeep = getCurrentElem().getLN().stream() + .filter(tln -> !Utils.lnClassEquals(tln.getLnClass(), monitoringLnClassEnum.value())) + .toList(); + getCurrentElem().unsetLN(); + getCurrentElem().getLN().addAll(lnToKeep); + } + + private void updateNewCreatedLnDaiValue(TLN tln, TExtRef tExtRef, String lnInst, ResumedDataTemplate daToUpdate) { + LNAdapter lnAdapter = new LNAdapter(this, tln); + String value = createVal(tExtRef); + lnAdapter.getCurrentElem().setInst(lnInst); + daToUpdate.setVal(value); + lnAdapter.updateDAI(daToUpdate); + } + + private String createVal(TExtRef tExtRef) { + String sourceLdName = getParentAdapter().getParentAdapter().getIEDAdapterByName(tExtRef.getIedName()) + .getLDeviceAdapterByLdInst(tExtRef.getSrcLDInst()).getLdName(); + String lnClass = !tExtRef.isSetSrcLNClass() ? TLLN0Enum.LLN_0.value() : tExtRef.getSrcLNClass().get(0); + return sourceLdName + "/" + lnClass + "." + tExtRef.getSrcCBName(); + } + } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/MonitoringLnClassEnum.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/MonitoringLnClassEnum.java new file mode 100644 index 000000000..70080c3e0 --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/MonitoringLnClassEnum.java @@ -0,0 +1,22 @@ +/* + * // SPDX-FileCopyrightText: 2023 RTE FRANCE + * // + * // SPDX-License-Identifier: Apache-2.0 + */ + +package org.lfenergy.compas.sct.commons.util; + +public enum MonitoringLnClassEnum { + LSVS("LSVS"), + LGOS("LGOS"); + + private final String value; + + MonitoringLnClassEnum(String v) { + value = v; + } + + public String value() { + return value; + } +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/SettingLDEPFCsvHelper.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/SettingLDEPFCsvHelper.java new file mode 100644 index 000000000..ee4c36817 --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/SettingLDEPFCsvHelper.java @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2023 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +import com.opencsv.bean.CsvBindByPosition; +import lombok.ToString; +import org.lfenergy.compas.sct.commons.dto.LDEPFSettings; + +import java.io.Reader; +import java.util.List; + + +/** + * This class is an implementation example for interface LDEPFSettings. + * It relies on a CSV file. + * + * @see CsvUtils + */ +public class SettingLDEPFCsvHelper implements LDEPFSettings { + + private final List settings ; + + /** + * Constructor + * @param reader input + */ + public SettingLDEPFCsvHelper(Reader reader) { + this.settings = CsvUtils.parseRows(reader, SettingLDEPF.class).stream().toList(); + } + + @Override + public List getSettings() { + return this.settings; + } + + @ToString + public static class SettingLDEPF { + @CsvBindByPosition(position = 0) + private String rteIedType; + @CsvBindByPosition(position = 1) + private String iedRedundancy; + @CsvBindByPosition(position = 2) + private String iedInstance; + @CsvBindByPosition(position = 3) + private String channelShortLabel; + @CsvBindByPosition(position = 4) + private String channelMREP; + @CsvBindByPosition(position = 5) + private String channelLevModQ; + @CsvBindByPosition(position = 6) + private String channelLevModLevMod; + @CsvBindByPosition(position = 7) + private String bapVariant; + @CsvBindByPosition(position = 8) + private String bapIgnoredValue; + @CsvBindByPosition(position = 9) + private String ldInst; + @CsvBindByPosition(position = 10) + private String lnPrefix; + @CsvBindByPosition(position = 11) + private String lnName; + @CsvBindByPosition(position = 12) + private String lnInst; + @CsvBindByPosition(position = 13) + private String doName; + @CsvBindByPosition(position = 14) + private String doInst; + @CsvBindByPosition(position = 15) + private String sdoName; + @CsvBindByPosition(position = 16) + private String daName; + @CsvBindByPosition(position = 17) + private String daType; + @CsvBindByPosition(position = 18) + private String dabType; + @CsvBindByPosition(position = 19) + private String bdaName; + @CsvBindByPosition(position = 20) + private String sbdaName; + @CsvBindByPosition(position = 21) + private String channelAnalogNum; + @CsvBindByPosition(position = 22) + private String channelDigitalNum; + @CsvBindByPosition(position = 23) + private String opt; + } +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java index f69176a2d..a9f80950d 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java @@ -5,7 +5,16 @@ package org.lfenergy.compas.sct.commons.util; import org.apache.commons.lang3.StringUtils; +import org.lfenergy.compas.scl2007b4.model.TExtRef; +import org.lfenergy.compas.scl2007b4.model.TLLN0Enum; +import org.lfenergy.compas.sct.commons.exception.ScdException; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.util.JAXBSource; +import javax.xml.namespace.QName; import java.util.*; import java.util.function.Function; import java.util.function.Predicate; @@ -23,6 +32,9 @@ public final class Utils { private static final long MAC_ADDRESS_MAX_VALUE = 0xFFFFFFFFFFFFL; private static final Pattern MAC_ADDRESS_PATTERN = Pattern.compile("[0-9A-F]{2}([-:][0-9A-F]{2}){5}", Pattern.CASE_INSENSITIVE); + private static JAXBContext jaxbContext = null; + private static Unmarshaller unmarshaller = null; + /** * Private Constructor, should not be instanced */ @@ -353,4 +365,45 @@ public static long macAddressToLong(String macAddress){ public static String toHex(long number, int length) { return StringUtils.leftPad(Long.toHexString(number).toUpperCase(), length, "0"); } + + /** + * creates a copy of Scl element + * + * @param object object to copy + * @param clazz class type of the object + * @param type of the object + * @return copy of the object + */ + public static T copySclElement(T object, Class clazz) { + try { + if (jaxbContext == null) { + jaxbContext = JAXBContext.newInstance("org.lfenergy.compas.scl2007b4.model"); + unmarshaller = jaxbContext.createUnmarshaller(); + } + JAXBElement contentObject = new JAXBElement<>(new QName(clazz.getSimpleName()), clazz, object); + JAXBSource source = new JAXBSource(jaxbContext, contentObject); + return unmarshaller.unmarshal(source, clazz).getValue(); + } catch (JAXBException e) { + throw new ScdException(e.getMessage(), e); + } + } + + /** + * Checks if two ExtRefs fed by same Control Block + * + * @param t1 extref to compare + * @param t2 extref to compare + * @return true if the two ExtRef are fed by same Control Block, otherwise false + */ + public static boolean isExtRefFeedBySameControlBlock(TExtRef t1, TExtRef t2) { + String srcLNClass1 = (t1.isSetSrcLNClass()) ? t1.getSrcLNClass().get(0) : TLLN0Enum.LLN_0.value(); + String srcLNClass2 = (t2.isSetSrcLNClass()) ? t2.getSrcLNClass().get(0) : TLLN0Enum.LLN_0.value(); + return Utils.equalsOrBothBlank(t1.getIedName(), t2.getIedName()) + && Utils.equalsOrBothBlank(t1.getSrcLDInst(), t2.getSrcLDInst()) + && srcLNClass1.equals(srcLNClass2) + && Utils.equalsOrBothBlank(t1.getSrcLNInst(), t2.getSrcLNInst()) + && Utils.equalsOrBothBlank(t1.getSrcPrefix(), t2.getSrcPrefix()) + && Utils.equalsOrBothBlank(t1.getSrcCBName(), t2.getSrcCBName()) + && Objects.equals(t1.getServiceType(), t2.getServiceType()); + } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/LDEPFSettingsTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/LDEPFSettingsTest.java new file mode 100644 index 000000000..ed5300bcc --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/LDEPFSettingsTest.java @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2023 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.dto; + +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.sct.commons.util.CsvUtils; +import org.lfenergy.compas.sct.commons.util.SettingLDEPFCsvHelper; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Objects; +import static org.assertj.core.api.Assertions.assertThat; + +class LDEPFSettingsTest { + + @Test + void getLDEPFSettings_should_return_settings() { + //Given + String fileName = "LDEPF_Setting_file.csv"; + InputStream inputStream = Objects.requireNonNull(CsvUtils.class.getClassLoader().getResourceAsStream(fileName), "Resource not found: " + fileName); + InputStreamReader reader = new InputStreamReader(inputStream); + LDEPFSettings ldepfSettings = new SettingLDEPFCsvHelper(reader); + // When + // Then + assertThat(ldepfSettings.getSettings()).hasSize(161); + } +} \ No newline at end of file diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplateTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplateTest.java index 585484f4e..988f9e0b1 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplateTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ResumedDataTemplateTest.java @@ -8,9 +8,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.lfenergy.compas.scl2007b4.model.TFCEnum; -import org.lfenergy.compas.scl2007b4.model.TPredefinedCDCEnum; -import org.lfenergy.compas.scl2007b4.model.TVal; +import org.lfenergy.compas.scl2007b4.model.*; +import org.lfenergy.compas.sct.commons.scl.ied.LNAdapter; import java.util.List; import java.util.Map; @@ -275,4 +274,27 @@ void setVal_should_replace_reference_val(){ assertThat(rDTT.getDaName().getDaiValues()).hasSize(1) .isEqualTo(Map.of(0L, "newValue")); } + + @Test + void constructorTest() { + // Given + TLN tln = new TLN(); + tln.setLnType("T1"); + tln.getLnClass().add(TLLN0Enum.LLN_0.value()); + tln.setPrefix("P1"); + LNAdapter lnAdapter = new LNAdapter(null, tln); + // When + ResumedDataTemplate expected = new ResumedDataTemplate(lnAdapter, "do", "da"); + // Then + assertThat(expected.getLnClass()).isEqualTo(TLLN0Enum.LLN_0.value()); + assertThat(expected.getLnType()).isEqualTo("T1"); + assertThat(expected.getPrefix()).isEqualTo("P1"); + assertThat(expected.getDoName().getName()).isEqualTo("do"); + assertThat(expected.getDoName().getName()).isEqualTo("do"); + assertThat(expected.getDoName().getStructNames()).isEmpty(); + assertThat(expected.getDaName().getName()).isEqualTo("da"); + assertThat(expected.getDaName().getDaiValues()).isEmpty(); + assertThat(expected.getDaName().isValImport()).isFalse(); + assertThat(expected.getDaName().isUpdatable()).isFalse(); + } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ExtRefServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ExtRefServiceTest.java index 9e453f223..673128728 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ExtRefServiceTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ExtRefServiceTest.java @@ -31,6 +31,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.lfenergy.compas.scl2007b4.model.TFCEnum.ST; import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.*; +import static org.lfenergy.compas.sct.commons.scl.ExtRefService.filterDuplicatedExtRefs; import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.*; import static org.lfenergy.compas.sct.commons.util.ControlBlockEnum.*; import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newDurationInMilliSec; @@ -509,4 +510,39 @@ public static Stream provideConfigureNetworkForAllControlBlocksErrors ); } + @Test + void filterDuplicatedExtRefs_should_remove_duplicated_extrefs() { + // Given + TExtRef tExtRefLnClass = createExtRefExample("CB_Name1", TServiceType.GOOSE); + tExtRefLnClass.getSrcLNClass().add(TLLN0Enum.LLN_0.value()); + TExtRef tExtRef = createExtRefExample("CB_Name1", TServiceType.GOOSE); + List tExtRefList = List.of(tExtRef, tExtRefLnClass, createExtRefExample("CB", TServiceType.GOOSE), + createExtRefExample("CB", TServiceType.GOOSE)); + // When + List result = filterDuplicatedExtRefs(tExtRefList); + // Then + assertThat(result).hasSizeLessThan(tExtRefList.size()) + .hasSize(2); + } + + @Test + void filterDuplicatedExtRefs_should_not_remove_not_duplicated_extrefs() { + // Given + TExtRef tExtRefIedName = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefIedName.setIedName("IED_XXX"); + TExtRef tExtRefLdInst = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefLdInst.setSrcLDInst("LD_XXX"); + TExtRef tExtRefLnInst = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefLnInst.setSrcLNInst("X"); + TExtRef tExtRefPrefix = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefPrefix.setSrcPrefix("X"); + List tExtRefList = List.of(tExtRefIedName, tExtRefLdInst, tExtRefLnInst, tExtRefPrefix, + createExtRefExample("CB_1", TServiceType.GOOSE), createExtRefExample("CB_1", TServiceType.SMV)); + // When + List result = filterDuplicatedExtRefs(tExtRefList); + // Then + assertThat(result).hasSameSizeAs(tExtRefList) + .hasSize(6); + } + } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclServiceTest.java index ca831e518..59d60b8f4 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclServiceTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclServiceTest.java @@ -27,11 +27,66 @@ import static org.junit.jupiter.api.Assertions.*; import static org.lfenergy.compas.sct.commons.testhelpers.DataTypeUtils.createDa; import static org.lfenergy.compas.sct.commons.testhelpers.DataTypeUtils.createDo; +import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.LD_SUIED; +import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.getDAIAdapters; import static org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller.assertIsMarshallable; import static org.lfenergy.compas.sct.commons.util.PrivateEnum.COMPAS_SCL_FILE_TYPE; class SclServiceTest { + private static Stream sclProviderMissingRequiredObjects() { + SCL scl1 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_KO_MissingBeh.scd"); + SCL scl2 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivate.scd"); + SCL scl3 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivateAttribute.scd"); + SCL scl4 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_KO_MissingMod.scd"); + Tuple[] scl1Errors = new Tuple[]{Tuple.tuple("The LDevice doesn't have a DO @name='Beh' OR its associated DA@fc='ST' AND DA@name='stVal'", + "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0")}; + Tuple[] scl2Errors = new Tuple[]{Tuple.tuple("The LDevice doesn't have a Private compas:LDevice.", + "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0")}; + Tuple[] scl3Errors = new Tuple[]{Tuple.tuple("The Private compas:LDevice doesn't have the attribute 'LDeviceStatus'", + "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0")}; + Tuple[] scl4Errors = new Tuple[]{Tuple.tuple("The LDevice doesn't have a DO @name='Mod'", + "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0")}; + return Stream.of( + Arguments.of("MissingDOBeh", scl1, scl1Errors), + Arguments.of("MissingLDevicePrivate", scl2, scl2Errors), + Arguments.of("MissingLDevicePrivateAttribute", scl3, scl3Errors), + Arguments.of("MissingDOMod", scl4, scl4Errors) + ); + } + + private static Stream sclProviderBasedLDeviceStatus() { + SCL scl1 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_LD_STATUS_ACTIVE.scd"); + SCL scl2 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_LD_STATUS_UNTESTED.scd"); + SCL scl3 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test1_LD_STATUS_INACTIVE.scd"); + Tuple[] scl1Errors = new Tuple[]{Tuple.tuple("The LDevice cannot be set to 'off' but has not been selected into SSD.", + "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), + Tuple.tuple("The LDevice cannot be set to 'on' but has been selected into SSD.", + "/SCL/IED[@name=\"IedName2\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), + Tuple.tuple("The LDevice cannot be activated or desactivated because its BehaviourKind Enum contains NOT 'on' AND NOT 'off'.", + "/SCL/IED[@name=\"IedName3\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0" + )}; + Tuple[] scl2Errors = new Tuple[]{Tuple.tuple("The LDevice cannot be set to 'off' but has not been selected into SSD.", + "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), + Tuple.tuple("The LDevice cannot be set to 'on' but has been selected into SSD.", + "/SCL/IED[@name=\"IedName2\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), + Tuple.tuple("The LDevice cannot be activated or desactivated because its BehaviourKind Enum contains NOT 'on' AND NOT 'off'.", + "/SCL/IED[@name=\"IedName3\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0" + )}; + Tuple[] scl3Errors = new Tuple[]{Tuple.tuple("The LDevice is not qualified into STD but has been selected into SSD.", + "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), + Tuple.tuple("The LDevice cannot be set to 'on' but has been selected into SSD.", + "/SCL/IED[@name=\"IedName2\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), + Tuple.tuple("The LDevice cannot be activated or desactivated because its BehaviourKind Enum contains NOT 'on' AND NOT 'off'.", + "/SCL/IED[@name=\"IedName3\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0" + )}; + return Stream.of( + Arguments.of("ACTIVE", scl1, scl1Errors), + Arguments.of("UNTESTED", scl2, scl2Errors), + Arguments.of("INACTIVE", scl3, scl3Errors) + ); + } + @Test void testAddHistoryItem() throws ScdException { SclRootAdapter sclRootAdapter = new SclRootAdapter("hId", SclRootAdapter.VERSION, SclRootAdapter.REVISION); @@ -890,27 +945,6 @@ void removeControlBlocksAndDatasetAndExtRefSrc_should_remove_srcXXX_attributes_o assertIsMarshallable(scl); } - private static Stream sclProviderMissingRequiredObjects() { - SCL scl1 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_KO_MissingBeh.scd"); - SCL scl2 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivate.scd"); - SCL scl3 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_KO_MissingLDevicePrivateAttribute.scd"); - SCL scl4 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_KO_MissingMod.scd"); - Tuple[] scl1Errors = new Tuple[]{Tuple.tuple("The LDevice doesn't have a DO @name='Beh' OR its associated DA@fc='ST' AND DA@name='stVal'", - "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0")}; - Tuple[] scl2Errors = new Tuple[]{Tuple.tuple("The LDevice doesn't have a Private compas:LDevice.", - "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0")}; - Tuple[] scl3Errors = new Tuple[]{Tuple.tuple("The Private compas:LDevice doesn't have the attribute 'LDeviceStatus'", - "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0")}; - Tuple[] scl4Errors = new Tuple[]{Tuple.tuple("The LDevice doesn't have a DO @name='Mod'", - "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0")}; - return Stream.of( - Arguments.of("MissingDOBeh", scl1, scl1Errors), - Arguments.of("MissingLDevicePrivate", scl2, scl2Errors), - Arguments.of("MissingLDevicePrivateAttribute", scl3, scl3Errors), - Arguments.of("MissingDOMod", scl4, scl4Errors) - ); - } - @ParameterizedTest(name = "{0}") @MethodSource("sclProviderMissingRequiredObjects") void updateLDeviceStatus_shouldReturnReportWithError_MissingRequiredObject(String testCase, SCL scl, Tuple... errors) { @@ -931,38 +965,6 @@ void updateLDeviceStatus_shouldReturnReportWithError_MissingRequiredObject(Strin assertEquals(before, after); } - private static Stream sclProviderBasedLDeviceStatus() { - SCL scl1 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_LD_STATUS_ACTIVE.scd"); - SCL scl2 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test_LD_STATUS_UNTESTED.scd"); - SCL scl3 = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/issue68_Test1_LD_STATUS_INACTIVE.scd"); - Tuple[] scl1Errors = new Tuple[]{Tuple.tuple("The LDevice cannot be set to 'off' but has not been selected into SSD.", - "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), - Tuple.tuple("The LDevice cannot be set to 'on' but has been selected into SSD.", - "/SCL/IED[@name=\"IedName2\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), - Tuple.tuple("The LDevice cannot be activated or desactivated because its BehaviourKind Enum contains NOT 'on' AND NOT 'off'.", - "/SCL/IED[@name=\"IedName3\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0" - )}; - Tuple[] scl2Errors = new Tuple[]{Tuple.tuple("The LDevice cannot be set to 'off' but has not been selected into SSD.", - "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), - Tuple.tuple("The LDevice cannot be set to 'on' but has been selected into SSD.", - "/SCL/IED[@name=\"IedName2\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), - Tuple.tuple("The LDevice cannot be activated or desactivated because its BehaviourKind Enum contains NOT 'on' AND NOT 'off'.", - "/SCL/IED[@name=\"IedName3\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0" - )}; - Tuple[] scl3Errors = new Tuple[]{Tuple.tuple("The LDevice is not qualified into STD but has been selected into SSD.", - "/SCL/IED[@name=\"IedName1\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), - Tuple.tuple("The LDevice cannot be set to 'on' but has been selected into SSD.", - "/SCL/IED[@name=\"IedName2\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0"), - Tuple.tuple("The LDevice cannot be activated or desactivated because its BehaviourKind Enum contains NOT 'on' AND NOT 'off'.", - "/SCL/IED[@name=\"IedName3\"]/AccessPoint/Server/LDevice[@inst=\"LDSUIED\"]/LN0" - )}; - return Stream.of( - Arguments.of("ACTIVE", scl1, scl1Errors), - Arguments.of("UNTESTED", scl2, scl2Errors), - Arguments.of("INACTIVE", scl3, scl3Errors) - ); - } - @ParameterizedTest(name = "{0}") @MethodSource("sclProviderBasedLDeviceStatus") void updateLDeviceStatus_shouldReturnReportWithError_WhenLDeviceStatusActiveOrUntestedOrInactive(String testCase, SCL scl, Tuple... errors) { @@ -1090,7 +1092,7 @@ private Optional getLDeviceStatusValue(SCL scl, String iedName, String ldI @ParameterizedTest(name = "{0}") @CsvSource({ "Test update setSrcRef Value,LD_WITH_1_InRef,InRef2,setSrcRef,IED_NAME1LD_WITH_1_InRef/PRANCR1.Do11.sdo11", - "Test update setSrcCB Value,LD_WITH_1_InRef,InRef2,setSrcCB,IED_NAME1LD_WITH_1_InRef/prefixANCR1.GSE1", + "Test update setSrcCB Value,LD_WITH_1_InRef,InRef2,setSrcCB,OLD_VAL", "Test update setSrcRef Value,LD_WITH_3_InRef,InRef3,setSrcRef,IED_NAME1LD_WITH_3_InRef/PRANCR1.Do11.sdo11", "Test update setSrcCB Value,LD_WITH_3_InRef,InRef3,setSrcCB,IED_NAME1LD_WITH_3_InRef/prefixANCR1.GSE1", "Test update setTstRef Value,LD_WITH_3_InRef,InRef3,setTstRef,IED_NAME1LD_WITH_3_InRef/PRANCR1.Do11.sdo11", @@ -1105,6 +1107,7 @@ void updateDoInRef_shouldReturnUpdatedFile(String testName, String ldInst, Strin // Then assertThat(sclReport.isSuccess()).isTrue(); + SclTestMarshaller.assertIsMarshallable(sclReport.getSclRootAdapter().currentElem); assertThat(getValFromDaiName(sclReport.getSclRootAdapter().getCurrentElem(), "IED_NAME1", ldInst, doName, daName) .map(TVal::getValue)) .hasValue(expected); @@ -1196,18 +1199,80 @@ void analyzeDataGroups_should_return_errors_messages() { assertThat(sclReport.getSclReportItems()).hasSize(11) .extracting(SclReportItem::getMessage) .containsExactlyInAnyOrder( - "The Client IED IED_NAME1 subscribes to too much FCDA: 9 > 8 max", - "The Client IED IED_NAME1 subscribes to too much GOOSE Control Blocks: 3 > 2 max", - "The Client IED IED_NAME1 subscribes to too much Report Control Blocks: 1 > 0 max", - "The Client IED IED_NAME1 subscribes to too much SMV Control Blocks: 2 > 1 max", - "There are too much FCDA for the DataSet dataset6 for the LDevice LD_INST21 in IED IED_NAME2: 2 > 1 max", - "There are too much FCDA for the DataSet dataset6 for the LDevice LD_INST22 in IED IED_NAME2: 2 > 1 max", - "There are too much FCDA for the DataSet dataset5 for the LDevice LD_INST22 in IED IED_NAME2: 2 > 1 max", - "There are too much DataSets for the IED IED_NAME2: 6 > 3 max", - "There are too much Report Control Blocks for the IED IED_NAME2: 1 > 0 max", - "There are too much GOOSE Control Blocks for the IED IED_NAME2: 3 > 2 max", - "There are too much SMV Control Blocks for the IED IED_NAME2: 3 > 1 max"); + "The Client IED IED_NAME1 subscribes to too much FCDA: 9 > 8 max", + "The Client IED IED_NAME1 subscribes to too much GOOSE Control Blocks: 3 > 2 max", + "The Client IED IED_NAME1 subscribes to too much Report Control Blocks: 1 > 0 max", + "The Client IED IED_NAME1 subscribes to too much SMV Control Blocks: 2 > 1 max", + "There are too much FCDA for the DataSet dataset6 for the LDevice LD_INST21 in IED IED_NAME2: 2 > 1 max", + "There are too much FCDA for the DataSet dataset6 for the LDevice LD_INST22 in IED IED_NAME2: 2 > 1 max", + "There are too much FCDA for the DataSet dataset5 for the LDevice LD_INST22 in IED IED_NAME2: 2 > 1 max", + "There are too much DataSets for the IED IED_NAME2: 6 > 3 max", + "There are too much Report Control Blocks for the IED IED_NAME2: 1 > 0 max", + "There are too much GOOSE Control Blocks for the IED IED_NAME2: 3 > 2 max", + "There are too much SMV Control Blocks for the IED IED_NAME2: 3 > 1 max"); } + @Test + void manageMonitoringLns_should_update_and_create_lsvs_and_goose() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/monitoring_lns/scd_monitoring_lsvs_lgos.xml"); + // When + SclReport sclReport = SclService.manageMonitoringLns(scd); + //Then + assertThat(sclReport.getSclReportItems()).isEmpty(); + LDeviceAdapter lDeviceAdapter = sclReport.getSclRootAdapter().getIEDAdapterByName("IED_NAME1").getLDeviceAdapterByLdInst(LD_SUIED); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(4) + .extracting(LNAdapter::getLNClass, LNAdapter::getLNInst).containsExactlyInAnyOrder( + Tuple.tuple("LGOS", "1"), Tuple.tuple("LGOS", "2"), + Tuple.tuple("LSVS", "1"), Tuple.tuple("LSVS", "2")); + SclTestMarshaller.assertIsMarshallable(sclReport.getSclRootAdapter().currentElem); + } + + @Test + void manageMonitoringLns_should_not_update_and_not_create_lsvs_and_goose_when_no_extRef() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/monitoring_lns/scd_monitoring_lsvs_lgos.xml"); + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + LDeviceAdapter lDeviceAdapter11 = sclRootAdapter.getIEDAdapterByName("IED_NAME1").getLDeviceAdapterByLdInst("LD_INST11"); + lDeviceAdapter11.getLN0Adapter().getCurrentElem().setInputs(null); + LDeviceAdapter lDeviceAdapter21 = sclRootAdapter.getIEDAdapterByName("IED_NAME1").getLDeviceAdapterByLdInst("LD_INST21"); + lDeviceAdapter21.getLN0Adapter().getCurrentElem().setInputs(null); + // When + SclReport sclReport = SclService.manageMonitoringLns(scd); + //Then + assertThat(sclReport.getSclReportItems()).isEmpty(); + LDeviceAdapter lDeviceAdapter = sclRootAdapter.getIEDAdapterByName("IED_NAME1").getLDeviceAdapterByLdInst(LD_SUIED); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(2) + .extracting(LNAdapter::getLNClass, LNAdapter::getLNInst).containsExactlyInAnyOrder( + Tuple.tuple("LGOS", "3"), Tuple.tuple("LSVS", "9")); + SclTestMarshaller.assertIsMarshallable(sclReport.getSclRootAdapter().currentElem); + } + + @Test + void manageMonitoringLns_should_not_update_and_not_create_lsvs_and_goose_when_dai_not_updatable() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/monitoring_lns/scd_monitoring_lsvs_lgos.xml"); + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + LDeviceAdapter lDeviceAdapter = sclRootAdapter.getIEDAdapterByName("IED_NAME1").getLDeviceAdapterByLdInst(LD_SUIED); + getDAIAdapters(lDeviceAdapter, "LGOS", "GoCBRef", "setSrcRef") + .forEach(daiAdapter -> daiAdapter.getCurrentElem().setValImport(false)); + getDAIAdapters(lDeviceAdapter, "LSVS", "SvCBRef", "setSrcRef") + .forEach(daiAdapter -> daiAdapter.getCurrentElem().setValImport(false)); + // When + SclReport sclReport = SclService.manageMonitoringLns(scd); + //Then + assertThat(sclReport.getSclReportItems()) + .isNotEmpty() + .hasSize(2) + .extracting(SclReportItem::getMessage) + .containsExactly("The DAI cannot be updated", "The DAI cannot be updated"); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(2) + .extracting(LNAdapter::getLNClass, LNAdapter::getLNInst).containsExactlyInAnyOrder( + Tuple.tuple("LGOS", "3"), Tuple.tuple("LSVS", "9")); + SclTestMarshaller.assertIsMarshallable(sclReport.getSclRootAdapter().currentElem); + } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java index fd02a8617..0aa5081a0 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java @@ -7,6 +7,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.assertj.core.groups.Tuple; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.dto.DaTypeName; import org.lfenergy.compas.sct.commons.dto.DoTypeName; @@ -15,6 +16,7 @@ import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; import org.lfenergy.compas.sct.commons.util.CommonConstants; +import org.mockito.junit.jupiter.MockitoExtension; import java.util.*; @@ -22,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newVal; +@ExtendWith(MockitoExtension.class) class DOIAdapterTest { @Test @@ -183,7 +186,7 @@ void DAIAdapter_update_when_valImport_is_set_to_false_but_da_is_Mod_StVal_should } @Test - void testFindDeepestMatch() throws Exception { + void testFindDeepestMatch() { // Given SCL scd = SclTestMarshaller.getSCLFromFile("/ied-test-schema-conf/ied_unit_test.xml"); SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); @@ -215,7 +218,6 @@ void testFindDeepestMatch() throws Exception { assertThat(pair.getLeft()).isInstanceOf(SDIAdapter.DAIAdapter.class); } - private DOIAdapter.DAIAdapter initInnerDAIAdapter(String doName, String daName) { TDOI tdoi = new TDOI(); tdoi.setName(doName); @@ -302,8 +304,7 @@ void findDataAdapterByName_should_return_DAIAdapter_when_DA_name_dont_exist() { @Test void updateDaiFromExtRef_should_update_setSrcXX_values_when_ExtRef_desc_suffix_ends_with_1() { // Given - DOIAdapter.DAIAdapter daiAdapter = initInnerDAIAdapter("Do", "da"); - DOIAdapter doiAdapter = daiAdapter.getParentAdapter(); + DOIAdapter doiAdapter = createDOIAdapterInScl(); TDAI daiSrcRef = new TDAI(); daiSrcRef.setName(DOIAdapter.DA_NAME_SET_SRC_REF); TDAI daiSrcCb = new TDAI(); @@ -331,8 +332,7 @@ private static Optional getDaiValOfDoi(DOIAdapter doiAdapter, String daNam @Test void updateDaiFromExtRef_should_update_setSrcRef_value_but_not_setSrcCB_when_ExtRef_dont_contains_CB() { // Given - DOIAdapter.DAIAdapter daiAdapter = initInnerDAIAdapter("Do", "da"); - DOIAdapter doiAdapter = daiAdapter.getParentAdapter(); + DOIAdapter doiAdapter = createDOIAdapterInScl(); TDAI daiSrcRef = new TDAI(); daiSrcRef.setName(DOIAdapter.DA_NAME_SET_SRC_REF); doiAdapter.getCurrentElem().getSDIOrDAI().add(daiSrcRef); @@ -353,8 +353,7 @@ void updateDaiFromExtRef_should_update_setSrcRef_value_but_not_setSrcCB_when_Ext @Test void updateDaiFromExtRef_should_update_setSrcXX_and_setTstXX_values_when_ExtRef_desc_suffix_ends_with_1_and_3() { // Given - DOIAdapter.DAIAdapter daiAdapter = initInnerDAIAdapter("Do", "da"); - DOIAdapter doiAdapter = daiAdapter.getParentAdapter(); + DOIAdapter doiAdapter = createDOIAdapterInScl(); TDAI daiSrcRef = new TDAI(); daiSrcRef.setName(DOIAdapter.DA_NAME_SET_SRC_REF); doiAdapter.getCurrentElem().getSDIOrDAI().add(daiSrcRef); @@ -406,8 +405,7 @@ private static TExtRef givenExtRef(int num, boolean withCbName) { @Test void updateDaiFromExtRef_should_update_only_setSrcRef_and_setTstRef_values_when_ExtRef_desc_suffix_ends_with_1_and_3_without_CB() { // Given - DOIAdapter.DAIAdapter daiAdapter = initInnerDAIAdapter("Do", "da"); - DOIAdapter doiAdapter = daiAdapter.getParentAdapter(); + DOIAdapter doiAdapter = createDOIAdapterInScl(); TDAI daiSrcRef = new TDAI(); daiSrcRef.setName(DOIAdapter.DA_NAME_SET_SRC_REF); doiAdapter.getCurrentElem().getSDIOrDAI().add(daiSrcRef); @@ -468,8 +466,7 @@ void updateDaiFromExtRef_should_return_warning_report_when_none_ExtRef_endin_wit @Test void updateDaiFromExtRef_should_create_DAI_when_no_DAI_name_setSrcRef() { // Given - DOIAdapter.DAIAdapter daiAdapter = initInnerDAIAdapter("Do", "da"); - DOIAdapter doiAdapter = daiAdapter.getParentAdapter(); + DOIAdapter doiAdapter = createDOIAdapterInScl(); TExtRef extRef1 = givenExtRef(1, false); @@ -504,8 +501,7 @@ void updateDaiFromExtRef_should_return_filled_ReportItem_when_no_ExtRef_in_LNode @Test void updateDaiFromExtRef_should_compose_correct_name_when_optional_ExtRef_attributes_are_missing() { // Given - DOIAdapter.DAIAdapter daiAdapter = initInnerDAIAdapter("Do", "da"); - DOIAdapter doiAdapter = daiAdapter.getParentAdapter(); + DOIAdapter doiAdapter = createDOIAdapterInScl(); TDAI daiSrcRef = new TDAI(); daiSrcRef.setName(DOIAdapter.DA_NAME_SET_SRC_REF); doiAdapter.getCurrentElem().getSDIOrDAI().add(daiSrcRef); @@ -569,4 +565,65 @@ void updateDaiFromExtRef_should_throw_exception_when_ExtRef_desc_dont_end_with__ assertThatThrownBy(() -> doiAdapter.updateDaiFromExtRef(extRefList)) .isInstanceOf(NumberFormatException.class); } + + private DOIAdapter createDOIAdapterInScl() { + TDOI tdoi = new TDOI(); + tdoi.setName("InRef"); + + LN0 ln0 = new LN0(); + ln0.setLnType("T1"); + ln0.getDOI().add(tdoi); + TLDevice tlDevice = new TLDevice(); + tlDevice.setInst("Inst"); + tlDevice.setLN0(ln0); + TServer tServer = new TServer(); + tServer.getLDevice().add(tlDevice); + TAccessPoint tAccessPoint = new TAccessPoint(); + tAccessPoint.setName("AP_NAME"); + tAccessPoint.setServer(tServer); + TIED tied = new TIED(); + tied.setName("IED_NAME"); + tied.getAccessPoint().add(tAccessPoint); + //SCL file + SCL scd = new SCL(); + scd.getIED().add(tied); + THeader tHeader = new THeader(); + tHeader.setRevision("1"); + scd.setHeader(tHeader); + // DataTypeTemplate + TLNodeType tlNodeType = new TLNodeType(); + tlNodeType.setId("T1"); + tlNodeType.getLnClass().add("LLN0"); + TDO tdo = new TDO(); + tdo.setName("InRef"); + tdo.setType("REF"); + tlNodeType.getDO().add(tdo); + TDOType tdoType = new TDOType(); + tdoType.setId("REF"); + TDA tda1 = createDa(DOIAdapter.DA_NAME_SET_SRC_REF); + TDA tda2 = createDa(DOIAdapter.DA_NAME_SET_SRC_CB); + TDA tda3 = createDa(DOIAdapter.DA_NAME_SET_TST_REF); + TDA tda4 = createDa(DOIAdapter.DA_NAME_SET_TST_CB); + tdoType.getSDOOrDA().addAll(List.of(tda1, tda2, tda3, tda4)); + + TDataTypeTemplates tDataTypeTemplates = new TDataTypeTemplates(); + tDataTypeTemplates.getLNodeType().add(tlNodeType); + tDataTypeTemplates.getDOType().add(tdoType); + scd.setDataTypeTemplates(tDataTypeTemplates); + + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + LN0Adapter ln0Adapter = sclRootAdapter.getIEDAdapterByName("IED_NAME").getLDeviceAdapterByLdInst("Inst").getLN0Adapter(); + + DOIAdapter doiAdapter = new DOIAdapter(ln0Adapter, tdoi); + return doiAdapter; + } + + private TDA createDa(String daName) { + TDA tda1 = new TDA(); + tda1.setName(daName); + tda1.setValImport(true); + tda1.setBType(TPredefinedBasicTypeEnum.OBJ_REF); + tda1.setFc(TFCEnum.SP); + return tda1; + } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapterTest.java index 7a3878135..a24685dd6 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapterTest.java @@ -5,6 +5,9 @@ package org.lfenergy.compas.sct.commons.scl.ied; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.dto.DTO; import org.lfenergy.compas.sct.commons.dto.ExtRefSignalInfo; @@ -14,6 +17,7 @@ import org.lfenergy.compas.sct.commons.scl.PrivateService; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; +import org.lfenergy.compas.sct.commons.util.MonitoringLnClassEnum; import org.mockito.Mockito; import java.util.HashMap; @@ -25,6 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.*; +import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.*; import static org.mockito.Mockito.mock; class IEDAdapterTest { @@ -205,7 +210,7 @@ void elementXPath() { } @Test - void checkDataGroupCoherence_should_succeed_no_error_message() throws Exception { + void checkDataGroupCoherence_should_succeed_no_error_message() { //Given IEDAdapter iedAdapter = provideIEDForCheckLimitationForIED(); //When @@ -215,7 +220,7 @@ void checkDataGroupCoherence_should_succeed_no_error_message() throws Exception } @Test - void checkDataGroupCoherence_should_fail_five_error_message() throws Exception { + void checkDataGroupCoherence_should_fail_five_error_message() { //Given IEDAdapter iedAdapter = provideIEDForCheckLimitationForIED(); iedAdapter.getCurrentElem().getAccessPoint().get(0).getServices().getConfDataSet().setMaxAttributes(2L); @@ -309,4 +314,115 @@ void getCompasSystemVersion_should_return_compas_icd_header(){ // Then assertThat(compasSystemVersion).map(TCompasSystemVersion::getMainSystemVersion).hasValue("01.00"); } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_not_update_ln_when_no_extRef(String testCase, MonitoringLnClassEnum lnClassEnum, String doName) { + // Given + IEDAdapter iedAdapter = createIedsInScl(lnClassEnum.value(), doName).getIEDAdapterByName(IED_NAME_1); + // When + List sclReportItems = iedAdapter.manageMonitoringLns(); + // Then + LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(LD_SUIED); + assertThat(sclReportItems).isEmpty(); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(1); + assertThat(lDeviceAdapter.getLNAdapters().get(0).getLNInst()).isNull(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_not_create_ln_when_no_init_ln(String testCase, MonitoringLnClassEnum lnClassEnum, String doName, TServiceType tServiceType) { + // Given + IEDAdapter iedAdapter = createIedsInScl(lnClassEnum.value(), doName).getIEDAdapterByName(IED_NAME_1); + TExtRef tExtRef = createExtRefExample("CB_Name", tServiceType); + LDeviceAdapter lDAdapter = iedAdapter.getLDeviceAdapterByLdInst("LD_ADD"); + lDAdapter.getLN0Adapter().getCurrentElem().getInputs().getExtRef().add(tExtRef); + LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(LD_SUIED); + lDeviceAdapter.getCurrentElem().unsetLN(); + // When + List sclReportItems = iedAdapter.manageMonitoringLns(); + // Then + assertThat(sclReportItems).isNotEmpty() + .extracting(SclReportItem::getMessage) + .containsExactly("There is no LN " + lnClassEnum.value() + " present in LDevice"); + assertThat(lDeviceAdapter.getLNAdapters()).isEmpty(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_update_ln_when_one_extRef_and_dai_updatable(String testCase, MonitoringLnClassEnum lnClassEnum, String doName, TServiceType tServiceType) { + // Given + IEDAdapter iedAdapter = createIedsInScl(lnClassEnum.value(), doName).getIEDAdapterByName(IED_NAME_1); + TExtRef tExtRef = createExtRefExample("CB_Name", tServiceType); + LDeviceAdapter lDAdapter = iedAdapter.getLDeviceAdapterByLdInst("LD_ADD"); + lDAdapter.getLN0Adapter().getCurrentElem().getInputs().getExtRef().add(tExtRef); + // When + List sclReportItems = iedAdapter.manageMonitoringLns(); + // Then + LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(LD_SUIED); + assertThat(sclReportItems).isEmpty(); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(1) + .map(LNAdapter::getLNInst) + .isEqualTo(List.of("1")); + assertThat(getDaiValues(lDeviceAdapter, lnClassEnum.value(), doName, "setSrcRef")) + .hasSize(1) + .extracting(TVal::getValue) + .containsExactly("LD_Name/LLN0.CB_Name"); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_not_update_ln_when_one_extRef_and_dai_not_updatable(String testCase, MonitoringLnClassEnum lnClassEnum, String doName, TServiceType tServiceType) { + // Given + SclRootAdapter sclRootAdapter = createIedsInScl(lnClassEnum.value(), doName); + sclRootAdapter.getDataTypeTemplateAdapter().getDOTypeAdapterById("REF").get().getDAAdapterByName("setSrcRef") + .get().getCurrentElem().setValImport(false); + IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(IED_NAME_1); + TExtRef tExtRef = createExtRefExample("CB_Name", tServiceType); + LDeviceAdapter lDAdapter = iedAdapter.getLDeviceAdapterByLdInst("LD_ADD"); + lDAdapter.getLN0Adapter().getCurrentElem().getInputs().getExtRef().add(tExtRef); + // When + List sclReportItems = iedAdapter.manageMonitoringLns(); + // Then + LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(LD_SUIED); + assertThat(sclReportItems).isNotEmpty() + .extracting(SclReportItem::getMessage) + .containsExactly("The DAI cannot be updated"); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(1); + assertThat(lDeviceAdapter.getLNAdapters().get(0).getLNInst()).isNull(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_update_ln_when_2_extRef_and_dai_updatable(String testCase, MonitoringLnClassEnum lnClassEnum, String doName, TServiceType tServiceType) { + // Given + IEDAdapter iedAdapter = createIedsInScl(lnClassEnum.value(), doName).getIEDAdapterByName(IED_NAME_1); + TExtRef tExtRef1 = createExtRefExample("CB_Name_1", tServiceType); + TExtRef tExtRef2 = createExtRefExample("CB_Name_2", tServiceType); + LDeviceAdapter lDAdapter = iedAdapter.getLDeviceAdapterByLdInst("LD_ADD"); + lDAdapter.getLN0Adapter().getCurrentElem().getInputs().getExtRef().addAll(List.of(tExtRef1, tExtRef2)); + // When + List sclReportItems = iedAdapter.manageMonitoringLns(); + // Then + LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(LD_SUIED); + assertThat(sclReportItems).isEmpty(); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(2) + .map(LNAdapter::getLNInst) + .isEqualTo(List.of("1", "2")); + assertThat(getDaiValues(lDeviceAdapter, lnClassEnum.value(), doName, "setSrcRef")) + .hasSize(2) + .extracting(TVal::getValue) + .containsExactly("LD_Name/LLN0.CB_Name_1", "LD_Name/LLN0.CB_Name_2"); + } + + private static Stream provideLnClassAndDoType() { + return Stream.of( + Arguments.of("Case GOOSE : ln LGOS", MonitoringLnClassEnum.LGOS, DO_GOCBREF, TServiceType.GOOSE), + Arguments.of("Case SMV : ln LSVS", MonitoringLnClassEnum.LSVS, DO_SVCBREF, TServiceType.SMV) + ); + } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapterTest.java index feb993360..638b4f036 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapterTest.java @@ -248,15 +248,56 @@ private static InputsAdapter keepOnlyThisExtRef(SclRootAdapter sclRootAdapter, S InputsAdapter foundInputsAdapter = sclRootAdapter.streamIEDAdapters() .flatMap(IEDAdapter::streamLDeviceAdapters) .filter(LDeviceAdapter::hasLN0) - .map(LDeviceAdapter::getLN0Adapter) - .filter(AbstractLNAdapter::hasInputs) - .map(LN0Adapter::getInputsAdapter) - .filter(inputsAdapter -> - inputsAdapter.getCurrentElem().getExtRef().stream().map(TExtRef::getDesc).anyMatch(extRefDesc::equals)) - .findFirst() - .orElseThrow(() -> new AssertionFailedError("ExtRef not found: " + extRefDesc)); + .map(LDeviceAdapter::getLN0Adapter) + .filter(AbstractLNAdapter::hasInputs) + .map(LN0Adapter::getInputsAdapter) + .filter(inputsAdapter -> + inputsAdapter.getCurrentElem().getExtRef().stream().map(TExtRef::getDesc).anyMatch(extRefDesc::equals)) + .findFirst() + .orElseThrow(() -> new AssertionFailedError("ExtRef not found: " + extRefDesc)); foundInputsAdapter.getCurrentElem().getExtRef().removeIf(Predicate.not(extref -> extRefDesc.equals(extref.getDesc()))); return foundInputsAdapter; } + @Test + void filterDuplicatedExtRefs_should_remove_duplicated_extrefs() { + // Given + TExtRef tExtRefLnClass = createExtRefExample("CB_Name1", TServiceType.GOOSE); + tExtRefLnClass.getSrcLNClass().add(TLLN0Enum.LLN_0.value()); + TExtRef tExtRef = createExtRefExample("CB_Name1", TServiceType.GOOSE); + List tExtRefList = List.of(tExtRef, tExtRefLnClass, createExtRefExample("CB", TServiceType.GOOSE), + createExtRefExample("CB", TServiceType.GOOSE)); + TInputs tInputs = new TInputs(); + tInputs.getExtRef().addAll(tExtRefList); + InputsAdapter inputsAdapter = new InputsAdapter(null, tInputs); + // When + List result = inputsAdapter.filterDuplicatedExtRefs(); + // Then + assertThat(result).hasSizeLessThan(tExtRefList.size()) + .hasSize(2); + } + + @Test + void filterDuplicatedExtRefs_should_not_remove_not_duplicated_extrefs() { + // Given + TExtRef tExtRefIedName = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefIedName.setIedName("IED_XXX"); + TExtRef tExtRefLdInst = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefLdInst.setSrcLDInst("LD_XXX"); + TExtRef tExtRefLnInst = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefLnInst.setSrcLNInst("X"); + TExtRef tExtRefPrefix = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefPrefix.setSrcPrefix("X"); + List tExtRefList = List.of(tExtRefIedName, tExtRefLdInst, tExtRefLnInst, tExtRefPrefix, + createExtRefExample("CB_1", TServiceType.GOOSE), createExtRefExample("CB_1", TServiceType.SMV)); + TInputs tInputs = new TInputs(); + tInputs.getExtRef().addAll(tExtRefList); + InputsAdapter inputsAdapter = new InputsAdapter(null, tInputs); + // When + List result = inputsAdapter.filterDuplicatedExtRefs(); + // Then + assertThat(result).hasSameSizeAs(tExtRefList) + .hasSize(6); + } + } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapterTest.java index f70c4fe04..25c5ea7b0 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapterTest.java @@ -13,22 +13,23 @@ import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.MethodSource; import org.lfenergy.compas.scl2007b4.model.*; -import org.lfenergy.compas.sct.commons.dto.DTO; -import org.lfenergy.compas.sct.commons.dto.ExtRefInfo; -import org.lfenergy.compas.sct.commons.dto.ExtRefSignalInfo; -import org.lfenergy.compas.sct.commons.dto.ResumedDataTemplate; +import org.lfenergy.compas.sct.commons.dto.*; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; import org.lfenergy.compas.sct.commons.util.ControlBlockEnum; +import org.lfenergy.compas.sct.commons.util.MonitoringLnClassEnum; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; +import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.*; import static org.lfenergy.compas.sct.commons.util.ControlBlockEnum.*; +import static org.lfenergy.compas.sct.commons.util.Utils.copySclElement; class LDeviceAdapterTest { @@ -453,8 +454,114 @@ void hasControlBlockCreationCapability_should_throw_exception_when_parameter_is_ // When & Then Assertions.assertThatThrownBy(() -> lDeviceAdapter.hasControlBlockCreationCapability(null)) - .isInstanceOf(NullPointerException.class); + .isInstanceOf(NullPointerException.class); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_not_update_ln_when_no_extRef(String testCase, MonitoringLnClassEnum lnClassEnum, String doName) { + // Given + LDeviceAdapter lDeviceAdapter = createIedsInScl(lnClassEnum.value(), doName).getIEDAdapterByName(IED_NAME_1).getLDeviceAdapterByLdInst(LD_SUIED); + // When + Optional sclReportItem = lDeviceAdapter.manageMonitoringLns(new ArrayList<>(), doName, lnClassEnum); + // Then + assertThat(sclReportItem).isNotPresent(); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(1); + assertThat(lDeviceAdapter.getLNAdapters().get(0).getLNInst()).isNull(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_not_create_ln_when_no_init_ln(String testCase, MonitoringLnClassEnum lnClassEnum, String doName) { + // Given + LDeviceAdapter lDeviceAdapter = createIedsInScl(lnClassEnum.value(), doName).getIEDAdapterByName(IED_NAME_1).getLDeviceAdapterByLdInst(LD_SUIED); + lDeviceAdapter.getCurrentElem().unsetLN(); + // When + Optional sclReportItem = lDeviceAdapter.manageMonitoringLns(List.of(new TExtRef()), doName, lnClassEnum); + // Then + assertThat(sclReportItem).isPresent(); + assertThat(sclReportItem.get()) + .extracting(SclReportItem::getMessage) + .isEqualTo("There is no LN " + lnClassEnum.value() + " present in LDevice"); + assertThat(lDeviceAdapter.getLNAdapters()).isEmpty(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_update_ln_when_one_extRef_and_dai_updatable(String testCase, MonitoringLnClassEnum lnClassEnum, String doName, TServiceType tServiceType) { + // Given + LDeviceAdapter lDeviceAdapter = createIedsInScl(lnClassEnum.value(), doName).getIEDAdapterByName(IED_NAME_1).getLDeviceAdapterByLdInst(LD_SUIED); + TExtRef tExtRef = createExtRefExample("CB_Name", tServiceType); + + // When + Optional sclReportItem = lDeviceAdapter.manageMonitoringLns(List.of(tExtRef), doName, lnClassEnum); + // Then + assertThat(sclReportItem).isNotPresent(); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(1) + .map(LNAdapter::getLNInst) + .isEqualTo(List.of("1")); + assertThat(getDaiValues(lDeviceAdapter, lnClassEnum.value(), doName, "setSrcRef")) + .hasSize(1) + .extracting(TVal::getValue) + .containsExactly("LD_Name/LLN0.CB_Name"); } + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_not_update_ln_when_one_extRef_and_dai_not_updatable(String testCase, MonitoringLnClassEnum lnClassEnum, String doName, TServiceType tServiceType) { + // Given + SclRootAdapter sclRootAdapter = createIedsInScl(lnClassEnum.value(), doName); + sclRootAdapter.getDataTypeTemplateAdapter().getDOTypeAdapterById("REF").get().getDAAdapterByName("setSrcRef") + .get().getCurrentElem().setValImport(false); + LDeviceAdapter lDeviceAdapter = sclRootAdapter.getIEDAdapterByName(IED_NAME_1).getLDeviceAdapterByLdInst(LD_SUIED); + TExtRef tExtRef = createExtRefExample("CB_Name", tServiceType); + + // When + Optional sclReportItem = lDeviceAdapter.manageMonitoringLns(List.of(tExtRef), doName, lnClassEnum); + // Then + assertThat(sclReportItem).isPresent(); + assertThat(sclReportItem.get()) + .extracting(SclReportItem::getMessage) + .isEqualTo("The DAI cannot be updated"); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(1); + assertThat(lDeviceAdapter.getLNAdapters().get(0).getLNInst()).isNull(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideLnClassAndDoType") + void manageMonitoringLns_should_update_ln_when_2_extRef_and_dai_updatable(String testCase, MonitoringLnClassEnum lnClassEnum, String doName, TServiceType tServiceType) { + // Given + LDeviceAdapter lDeviceAdapter = createIedsInScl(lnClassEnum.value(), doName).getIEDAdapterByName(IED_NAME_1).getLDeviceAdapterByLdInst(LD_SUIED); + TLN copiedLN1 = copySclElement(lDeviceAdapter.getLNAdapters().get(0).getCurrentElem(), TLN.class); + copiedLN1.setInst("23"); + TLN copiedLN2 = copySclElement(lDeviceAdapter.getLNAdapters().get(0).getCurrentElem(), TLN.class); + copiedLN2.setInst("24"); + lDeviceAdapter.getCurrentElem().getLN().addAll(List.of(copiedLN1, copiedLN2)); + TExtRef tExtRef1 = createExtRefExample("CB_Name_1", tServiceType); + TExtRef tExtRef2 = createExtRefExample("CB_Name_2", tServiceType); + + // When + Optional sclReportItem = lDeviceAdapter.manageMonitoringLns(List.of(tExtRef1, tExtRef2), doName, lnClassEnum); + // Then + assertThat(sclReportItem).isNotPresent(); + assertThat(lDeviceAdapter.getLNAdapters()) + .hasSize(2) + .map(LNAdapter::getLNInst) + .isEqualTo(List.of("1", "2")); + assertThat(getDaiValues(lDeviceAdapter, lnClassEnum.value(), doName, "setSrcRef")) + .hasSize(2) + .extracting(TVal::getValue) + .containsExactly("LD_Name/LLN0.CB_Name_1", "LD_Name/LLN0.CB_Name_2"); + } + + private static Stream provideLnClassAndDoType() { + return Stream.of( + Arguments.of("Case GOOSE : ln LGOS", MonitoringLnClassEnum.LGOS, DO_GOCBREF, TServiceType.GOOSE), + Arguments.of("Case SMV : ln LSVS", MonitoringLnClassEnum.LSVS, DO_SVCBREF, TServiceType.SMV) + ); + } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LN0AdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LN0AdapterTest.java index 0829dbcba..f7b9a243b 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LN0AdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/LN0AdapterTest.java @@ -29,8 +29,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Named.named; import static org.lfenergy.compas.scl2007b4.model.TSampledValueControl.SmvOpts; -import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.findLn0; -import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.getDaiValue; +import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -312,17 +311,17 @@ void testGetDOIAdapters() { @Test void findDoiAdapterByName_should_find_DOI(){ // Given - LN0Adapter ln0Adapter = createLn0AdapterWithDoi("doi1"); + LN0Adapter ln0Adapter = createLn0AdapterWithDoi("doi2"); // When - Optional result = ln0Adapter.findDoiAdapterByName("doi1"); + Optional result = ln0Adapter.findDoiAdapterByName("doi2"); // Then - assertThat(result).map(DOIAdapter::getName).hasValue("doi1"); + assertThat(result).map(DOIAdapter::getName).hasValue("doi2"); } @Test void findDoiAdapterByName_should_return_empty(){ // Given - LN0Adapter ln0Adapter = createLn0AdapterWithDoi("doi1"); + LN0Adapter ln0Adapter = createLn0AdapterWithDoi("doi3"); // When Optional result = ln0Adapter.findDoiAdapterByName("doi2"); // Then @@ -332,17 +331,17 @@ void findDoiAdapterByName_should_return_empty(){ @Test void getDOIAdapterByName_should_return_DOI(){ // Given - LN0Adapter ln0Adapter = createLn0AdapterWithDoi("doi1"); + LN0Adapter ln0Adapter = createLn0AdapterWithDoi("doi4"); // When - DOIAdapter result = ln0Adapter.getDOIAdapterByName("doi1"); + DOIAdapter result = ln0Adapter.getDOIAdapterByName("doi4"); // Then - assertThat(result.getName()).isEqualTo("doi1"); + assertThat(result.getName()).isEqualTo("doi4"); } @Test void getDOIAdapterByName_should_throw_exception(){ // Given - LN0Adapter ln0Adapter = createLn0AdapterWithDoi("doi1"); + LN0Adapter ln0Adapter = createLn0AdapterWithDoi("doi5"); // When & Then assertThatThrownBy(() -> ln0Adapter.getDOIAdapterByName("doi2")) .isInstanceOf(ScdException.class); @@ -1052,7 +1051,42 @@ void updateDoInRef_should_update_setSrcRef_and_setSrcCB_and_setTstRef_and_setTst } @Test - void streamControlBlocks_should_return_all_GSEControlBlocks(){ + void updateDoInRef_should_not_update_setSrcRef_and_setSrcCB_and_setTstRef_and_setTstCB_when_ExtRef_desc_matches_and_dais_not_updatable() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-test-update-inref/scd_update_inref_test.xml"); + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + LN0Adapter sourceLn0 = findLn0(sclRootAdapter, "IED_NAME1", "LD_WITH_3_InRef"); + String doiNameInRef = "InRef3"; + findDai(sourceLn0, "InRef3" + "." + DOIAdapter.DA_NAME_SET_SRC_REF).update(0L, "OLD_VAL"); + findDai(sourceLn0, "InRef3" + "." + DOIAdapter.DA_NAME_SET_TST_REF).update(0L, "OLD_VAL"); + findDai(sourceLn0, "InRef3" + "." + DOIAdapter.DA_NAME_SET_SRC_REF).getCurrentElem().setValImport(false); + findDai(sourceLn0, "InRef3" + "." + DOIAdapter.DA_NAME_SET_SRC_CB).getCurrentElem().setValImport(false); + findDai(sourceLn0, "InRef3" + "." + DOIAdapter.DA_NAME_SET_TST_REF).getCurrentElem().setValImport(false); + findDai(sourceLn0, "InRef3" + "." + DOIAdapter.DA_NAME_SET_TST_CB).getCurrentElem().setValImport(false); + String expectedVal = "OLD_VAL"; + + // When + List sclReportItems = sourceLn0.updateDoInRef(); + // Then + + String finalSetSrcRef = getDaiValue(sourceLn0, doiNameInRef, DOIAdapter.DA_NAME_SET_SRC_REF); + String finalSetSrcCB = getDaiValue(sourceLn0, doiNameInRef, DOIAdapter.DA_NAME_SET_SRC_CB); + String finalSetTstRef = getDaiValue(sourceLn0, doiNameInRef, DOIAdapter.DA_NAME_SET_TST_REF); + String finalSetTstCB = getDaiValue(sourceLn0, doiNameInRef, DOIAdapter.DA_NAME_SET_TST_CB); + + assertThat(finalSetSrcRef).isEqualTo(expectedVal); + assertThat(finalSetSrcCB).isEqualTo(expectedVal); + assertThat(finalSetTstRef).isEqualTo(expectedVal); + assertThat(finalSetTstCB).isEqualTo(expectedVal); + assertThat(sclReportItems) + .hasSize(1) + .extracting(SclReportItem::getMessage) + .containsExactly("The DAI cannot be updated"); + } + + + @Test + void streamControlBlocks_should_return_all_GSEControlBlocks() { // Given IEDAdapter iedAdapter = mock(IEDAdapter.class); TLDevice tlDevice = new TLDevice(); diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclHelper.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclHelper.java index 07d957a36..835e4d459 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclHelper.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclHelper.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newConnectedAp; +import static org.lfenergy.compas.sct.commons.util.Utils.lnClassEquals; /** * Provides static methods to quickly retrieve SCL elements, to be used in writing tests. @@ -29,6 +30,12 @@ @UtilityClass public class SclHelper { + public static final String DO_GOCBREF = "GoCBRef"; + public static final String DO_SVCBREF = "SvCBRef"; + public static final String LD_SUIED = "LDSUIED"; + public static final String IED_NAME_1 = "IED_NAME_1"; + public static final String IED_NAME_2 = "IED_NAME_2"; + public static IEDAdapter findIed(SclRootAdapter sclRootAdapter, String iedName) { return sclRootAdapter.findIedAdapterByName(iedName) .orElseThrow(() -> new AssertionFailedError(String.format("IED.name=%s not found", iedName))); @@ -245,4 +252,107 @@ public static SclRootAdapter createSclRootWithConnectedAp(String iedName, String subNetwork.getConnectedAP().add(newConnectedAp(iedName, apName)); return sclRootAdapter; } + + public static TExtRef createExtRefExample(String cbName, TServiceType tServiceType) { + TExtRef tExtRef = new TExtRef(); + tExtRef.setIedName("IED_NAME_2"); + tExtRef.setServiceType(tServiceType); + tExtRef.setSrcLDInst("Inst_2"); + tExtRef.setSrcLNInst("LN"); + tExtRef.setSrcPrefix("Prefix"); + tExtRef.setSrcCBName(cbName); + return tExtRef; + } + + public static SclRootAdapter createIedsInScl(String lnClass, String doName) { + // DataTypeTemplate + TDO tdo = new TDO(); + tdo.setName(doName); + tdo.setType("REF"); + TLNodeType tlNodeType = new TLNodeType(); + tlNodeType.setId("T1"); + tlNodeType.getLnClass().add(lnClass); + tlNodeType.getDO().add(tdo); + + TDA tda = new TDA(); + tda.setName("setSrcRef"); + tda.setValImport(true); + tda.setBType(TPredefinedBasicTypeEnum.OBJ_REF); + tda.setFc(TFCEnum.SP); + + TDOType tdoType = new TDOType(); + tdoType.setId("REF"); + tdoType.getSDOOrDA().add(tda); + + TDataTypeTemplates tDataTypeTemplates = new TDataTypeTemplates(); + tDataTypeTemplates.getLNodeType().add(tlNodeType); + tDataTypeTemplates.getDOType().add(tdoType); + + + //ied Client + TDOI tdoi = new TDOI(); + tdoi.setName(doName); + TLDevice tlDevice = new TLDevice(); + tlDevice.setInst("LD_ADD"); + TInputs tInputs = new TInputs(); + LN0 ln0 = new LN0(); + ln0.setInputs(tInputs); + tlDevice.setLN0(ln0); + + TLDevice tlDevice1 = new TLDevice(); + tlDevice1.setLN0(new LN0()); + tlDevice1.setInst(LD_SUIED); + TLN tln1 = new TLN(); + tln1.getLnClass().add(lnClass); + tln1.setLnType("T1"); + tln1.getDOI().add(tdoi); + tlDevice1.getLN().add(tln1); + TServer tServer1 = new TServer(); + tServer1.getLDevice().add(tlDevice1); + tServer1.getLDevice().add(tlDevice); + TAccessPoint tAccessPoint1 = new TAccessPoint(); + tAccessPoint1.setName("AP_NAME"); + tAccessPoint1.setServer(tServer1); + TIED tied1 = new TIED(); + tied1.setName(IED_NAME_1); + tied1.getAccessPoint().add(tAccessPoint1); + + //ied Source + TLDevice tlDevice2 = new TLDevice(); + tlDevice2.setInst("Inst_2"); + tlDevice2.setLdName("LD_Name"); + tlDevice2.setLN0(new LN0()); + TServer tServer2 = new TServer(); + tServer2.getLDevice().add(tlDevice2); + TAccessPoint tAccessPoint2 = new TAccessPoint(); + tAccessPoint2.setName("AP_NAME"); + tAccessPoint2.setServer(tServer2); + TIED tied2 = new TIED(); + tied2.setName(IED_NAME_2); + tied2.getAccessPoint().add(tAccessPoint2); + //SCL file + SCL scd = new SCL(); + scd.getIED().add(tied1); + scd.getIED().add(tied2); + THeader tHeader = new THeader(); + tHeader.setRevision("1"); + scd.setHeader(tHeader); + scd.setDataTypeTemplates(tDataTypeTemplates); + + return new SclRootAdapter(scd); + } + + public static List getDaiValues(LDeviceAdapter lDeviceAdapter, String lnClass, String doName, String daName) { + return getDAIAdapters(lDeviceAdapter, lnClass, doName, daName) + .map(daiAdapter -> daiAdapter.getCurrentElem().getVal()) + .flatMap(List::stream) + .toList(); + } + + public static Stream getDAIAdapters(LDeviceAdapter lDeviceAdapter, String lnClass, String doName, String daName) { + return lDeviceAdapter.getLNAdapters().stream() + .filter(lnAdapter -> lnClassEquals(lnAdapter.getCurrentElem().getLnClass(), lnClass)) + .map(lnAdapter -> lnAdapter.getDOIAdapterByName(doName)) + .map(doiAdapter -> (DOIAdapter.DAIAdapter) doiAdapter.getDataAdapterByName(daName)); + } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/MonitoringLnClassEnumTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/MonitoringLnClassEnumTest.java new file mode 100644 index 000000000..5363c3d83 --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/MonitoringLnClassEnumTest.java @@ -0,0 +1,24 @@ +/* + * // SPDX-FileCopyrightText: 2023 RTE FRANCE + * // + * // SPDX-License-Identifier: Apache-2.0 + */ + +package org.lfenergy.compas.sct.commons.util; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class MonitoringLnClassEnumTest { + + @Test + void value_should_return_string_value() { + // Given + // When + // Then + assertThat(MonitoringLnClassEnum.LSVS.value()).isEqualTo("LSVS"); + assertThat(MonitoringLnClassEnum.LGOS.value()).isEqualTo("LGOS"); + } + +} \ No newline at end of file diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/SettingLDEPFCsvHelperTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/SettingLDEPFCsvHelperTest.java new file mode 100644 index 000000000..62d5af732 --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/SettingLDEPFCsvHelperTest.java @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2023 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +import org.junit.jupiter.api.Test; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Objects; + +import static org.assertj.core.api.Assertions.assertThat; + + +class SettingLDEPFCsvHelperTest { + + @Test + void readCsvFile_should_return_settings() { + // Given + String fileName = "LDEPF_Setting_file.csv"; + InputStream inputStream = Objects.requireNonNull(CsvUtils.class.getClassLoader().getResourceAsStream(fileName), "Resource not found: " + fileName); + InputStreamReader reader = new InputStreamReader(inputStream); + // When + // Then + SettingLDEPFCsvHelper settingLDEPFCsvHelper = new SettingLDEPFCsvHelper(reader); + assertThat(settingLDEPFCsvHelper.getSettings()).hasSize(161); + } +} \ No newline at end of file diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java index 525239889..b0330603a 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java @@ -11,14 +11,21 @@ import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import org.junit.platform.commons.support.ReflectionSupport; +import org.lfenergy.compas.scl2007b4.model.TExtRef; +import org.lfenergy.compas.scl2007b4.model.TLLN0Enum; +import org.lfenergy.compas.scl2007b4.model.TLN; +import org.lfenergy.compas.scl2007b4.model.TServiceType; +import org.lfenergy.compas.sct.commons.dto.FCDAInfo; +import org.lfenergy.compas.sct.commons.exception.ScdException; import java.util.*; import java.util.stream.Stream; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Named.named; +import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.createExtRefExample; +import static org.lfenergy.compas.sct.commons.util.Utils.copySclElement; class UtilsTest { @@ -537,11 +544,86 @@ void macAddressToLong_when_malformed_macAddress_should_throw_exception(String ma @ParameterizedTest @CsvSource({"0,6,000000", "255,1,FF", "255,2,FF", "255,3,0FF", "10,2,0A"}) - void toHex_should_return_hexadecimal(long number, int length, String expected){ + void toHex_should_return_hexadecimal(long number, int length, String expected) { // Given // When String result = Utils.toHex(number, length); // Then assertThat(result).isEqualTo(expected); } + + @Test + void isExtRefFeedBySameControlBlock_should_return_true() { + // Given + TExtRef tExtRefLnClass = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefLnClass.getSrcLNClass().add(TLLN0Enum.LLN_0.value()); + TExtRef tExtRef = createExtRefExample("CB_1", TServiceType.GOOSE); + // When + // Then + assertThat(Utils.isExtRefFeedBySameControlBlock(tExtRef, tExtRefLnClass)).isTrue(); + assertThat(Utils.isExtRefFeedBySameControlBlock(createExtRefExample("CB_1", TServiceType.GOOSE), tExtRef)).isTrue(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideExtRefsToCompare") + void isExtRefFeedBySameControlBlock_should_return_false(String testCase, TExtRef tExtRef1, TExtRef tExtRef2) { + // Given + // When + // Then + assertThat(Utils.isExtRefFeedBySameControlBlock(tExtRef1, tExtRef2)).isFalse(); + } + + private static Stream provideExtRefsToCompare() { + TExtRef tExtRefLnClass = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefLnClass.getSrcLNClass().add("XXX"); + TExtRef tExtRefIedName = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefIedName.setIedName("IED_XXX"); + TExtRef tExtRefLdInst = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefLdInst.setSrcLDInst("LD_XXX"); + TExtRef tExtRefLnInst = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefLnInst.setSrcLNInst("X"); + TExtRef tExtRefPrefix = createExtRefExample("CB_1", TServiceType.GOOSE); + tExtRefPrefix.setSrcPrefix("X"); + + return Stream.of( + Arguments.of("ExtRef is not fed by same CB when different ServiceType", createExtRefExample("CB_1", TServiceType.GOOSE), + createExtRefExample("CB_1", TServiceType.SMV)), + Arguments.of("ExtRef is not fed by same CB when different SrcCBName", createExtRefExample("CB_1", TServiceType.GOOSE), + createExtRefExample("CB_2", TServiceType.GOOSE)), + Arguments.of("ExtRef is not fed by same CB when different SrcLnClass", createExtRefExample("CB_1", TServiceType.GOOSE), + tExtRefLnClass), + Arguments.of("ExtRef is not fed by same CB when different IedName", createExtRefExample("CB_1", TServiceType.GOOSE), + tExtRefIedName), + Arguments.of("ExtRef is not fed by same CB when different SrcLdInst", createExtRefExample("CB_1", TServiceType.GOOSE), + tExtRefLdInst), + Arguments.of("ExtRef is not fed by same CB when different SrcLnInst", createExtRefExample("CB_1", TServiceType.GOOSE), + tExtRefLnInst), + Arguments.of("ExtRef is not fed by same CB when different SrcPrefix", createExtRefExample("CB_1", TServiceType.GOOSE), + tExtRefPrefix) + ); + } + + @Test + void copySclElement_should_copy_by_value() { + // Given + TLN tln = new TLN(); + tln.setLnType("T1"); + tln.getLnClass().add(TLLN0Enum.LLN_0.value()); + // When + TLN result = copySclElement(tln, TLN.class); + // Then + assertThat(result).isNotSameAs(tln); + assertThat(result).usingRecursiveComparison().isEqualTo(tln); + } + + @Test + void copySclElement_should_throwException() { + // Given + FCDAInfo fcdaInfo = new FCDAInfo(); + // When + // Then + assertThatCode(() -> copySclElement(fcdaInfo, FCDAInfo.class)) + .isInstanceOf(ScdException.class) + .hasMessage("org.lfenergy.compas.sct.commons.dto.FCDAInfo is not known to this context"); + } } diff --git a/sct-commons/src/test/resources/LDEPF_Setting_file.csv b/sct-commons/src/test/resources/LDEPF_Setting_file.csv new file mode 100644 index 000000000..4f3f5d981 --- /dev/null +++ b/sct-commons/src/test/resources/LDEPF_Setting_file.csv @@ -0,0 +1,166 @@ +# SPDX-FileCopyrightText: 2023 RTE FRANCE +# +# SPDX-License-Identifier: Apache-2.0 + +#RTE-IEDType,IED.redundancy,IED.instance,Channel.ShortLabel,Channel.MREP,Channel.LevMod.q,Channel.LevMod,BAP.Variant,BAP.Ignored Value,LD.inst,LN.prefix,LN.name,LN.inst,DO.name,DO.inst,SDO.name,DA.name,DA.type,DA.bType,BDA.name,SBDA.name,Channel.Analog.num,Channel.Digital.num,Opt +BCU,None,1,MR.PX1,X,Other,Positive or Rising,8,N/A,LDPX,,PTRC,0,Str,0,,general,,BOOLEAN,,,,1,P0 +BCU,None,1,DT.PX1,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,general,,BOOLEAN,,,,2,P0 +BCU,None,1,MR.PX1.ZONE 1,,??,Other,NA,N/A,LDPX,,PDIS,1,Op,0,,general,,BOOLEAN,,,,3,P1 +BCU,None,1,MR.PX1.ZONE 2,,??,Other,NA,N/A,LDPX,,PDIS,2,Op,0,,general,,BOOLEAN,,,,4,P1 +BCU,None,1,MR.PX1.ZONE 3,,??,Other,NA,N/A,LDPX,,PDIS,3,Op,0,,general,,BOOLEAN,,,,5,P1 +BCU,None,1,MR.PX1.ZONE 4,,??,Other,NA,N/A,LDPX,,PDIS,4,Op,0,,general,,BOOLEAN,,,,6,P2 +BCU,None,1,MR.PX1.ZONE 5,,??,Other,NA,N/A,LDPX,,PDIS,5,Op,0,,general,,BOOLEAN,,,,7,P2 +BCU,None,1,MR.PX1.ZONE 6,,??,Other,NA,N/A,LDPX,,PDIS,6,Op,0,,general,,BOOLEAN,,,,8,P2 +BCU,None,1,MR.PX1.TERRE,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,neut,,BOOLEAN,,,,9,P0 +BCU,None,1,DT.PX1.PHASE *,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,phsA,,BOOLEAN,,,,10,P0 +BCU,None,1,DT.PX1.PHASE *,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,phsB,,BOOLEAN,,,,11,P0 +BCU,None,1,DT.PX1.PHASE *,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,phsC,,BOOLEAN,,,,12,P0 +BCU,None,1,MR.PX1.AMONT,,??,Other,NA,N/A,LDPX,,PTRC,0,Str,0,,dirGeneral,,BOOLEAN,,,,13,P0 +BCU,None,1,MR.PX1.AVAL,,??,Other,NA,N/A,LDPX,,,,,,,,,,,,,14,P0 +BPU,None,1,MR.PX2,X,Other,Positive or Rising,8,N/A,LDPX,,PTRC,0,Str,0,,general,,BOOLEAN,,,,15,P0 +BPU,None,1,DT.PX2,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,general,,BOOLEAN,,,,16,P0 +BPU,None,1,MR.PX2.ZONE 1,,??,Other,NA,N/A,LDPX,,PDIS,1,Op,0,,general,,BOOLEAN,,,,17,P1 +BPU,None,1,MR.PX2.ZONE 2,,??,Other,NA,N/A,LDPX,,PDIS,2,Op,0,,general,,BOOLEAN,,,,18,P1 +BPU,None,1,MR.PX2.ZONE 3,,??,Other,NA,N/A,LDPX,,PDIS,3,Op,0,,general,,BOOLEAN,,,,19,P1 +BPU,None,1,MR.PX2.ZONE 4,,??,Other,NA,N/A,LDPX,,PDIS,4,Op,0,,general,,BOOLEAN,,,,20,P2 +BPU,None,1,MR.PX2.ZONE 5,,??,Other,NA,N/A,LDPX,,PDIS,5,Op,0,,general,,BOOLEAN,,,,21,P2 +BPU,None,1,MR.PX2.ZONE 6,,??,Other,NA,N/A,LDPX,,PDIS,6,Op,0,,general,,BOOLEAN,,,,22,P2 +BPU,None,1,MR.PX2.TERRE,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,neut,,BOOLEAN,,,,23,P0 +BPU,None,1,DT.PX2.PHASE *,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,phsA,,BOOLEAN,,,,24,P0 +BPU,None,1,DT.PX2.PHASE *,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,phsB,,BOOLEAN,,,,25,P0 +BPU,None,1,DT.PX2.PHASE *,,??,Other,NA,N/A,LDPX,,PTRC,0,Op,0,,phsC,,BOOLEAN,,,,26,P0 +BPU,None,1,MR.PX2.AMONT,,??,Other,NA,N/A,LDPX,,PTRC,0,Str,0,,dirGeneral,,BOOLEAN,,,,27,P0 +BPU,None,1,MR.PX2.AVAL,,??,Other,NA,N/A,LDPX,,PTRC,0,,,,,,,,,,28,P0 +BCU,None,1,REC.ACCx.Vy,X,Other,Positive or Rising,8,N/A,LDPX,,PSCH,0,,,,,,,,,,29,P0 +BCU,None,1,REC.AUTx.Vy,X,Other,Positive or Rising,8,N/A,LDPX,,PSCH,0,,,,,,,,,,30,P0 +BCU,None,1,REC.VERx.Vy,X,Other,Positive or Rising,8,N/A,LDPX,,PSCH,0,,,,,,,,,,31,P0 +BCU,None,1,EMI.ACCx.Vy,,??,Other,NA,N/A,LDPX,,PSCH,0,TxPrm,0,,general,,BOOLEAN,,,,32,P0 +BCU,None,1,EMI.AUTx.Vy,,??,Other,NA,N/A,LDPX,,PSCH,0,TxPrm,0,,general,,BOOLEAN,,,,33,P0 +BCU,None,1,EMI.VERx.Vy,,??,Other,NA,N/A,LDPX,,PSCH,0,TxBlk,0,,general,,BOOLEAN,,,,34,P0 +BCU,None,1,MR.PW,X,Other,Positive or Rising,8,N/A,LDPW,,PTRC,0,Str,0,,general,,BOOLEAN,,,,35,P0 +BCU,None,1,MR.PW.AMONT,,??,Other,NA,N/A,LDPW,,PTRC,0,Str,0,,dirGeneral,,BOOLEAN,,,,36,P1 +BCU,None,1,DT.PW,,??,Other,NA,N/A,LDPW,,PTRC,0,Op,0,,general,,BOOLEAN,,,,37,P0 +BCU,None,1,MR.PCDH,X,Other,Positive or Rising,8,N/A,LDPCDH,,PTRC,0,Str,0,,general,,BOOLEAN,,,,38,P0 +BCU,None,1,EMI.AUT.PCDH,,??,Other,NA,N/A,LDPCDH,,PTRC,0,Op,0,,general,,BOOLEAN,,,,39,P0 +BCU,None,1,EMI.TD.PCDH,,??,Other,NA,N/A,LDPCDH,,PSCH,0,TxPrm,0,,general,,BOOLEAN,,,,40,P0 +BCU,None,1,REC.AUT.PCDH,X,Other,Positive or Rising,8,N/A,LDPCDH,,PSCH,0,,,,,,,,,,41,P0 +BCU,None,1,MR.PAP1,X,Other,Positive or Rising,8,N/A,LDPAP,,PTRC,0,Str,0,,general,,BOOLEAN,,,,42,P0 +BCU,None,1,DT.PAP1,,??,Other,NA,N/A,LDPAP,,PTRC,0,Op,0,,general,,BOOLEAN,,,,43,P0 +BCU,None,1,MR.PAP1.PHASE *,X,Other,Positive or Rising,8,N/A,LDPAP,,PTRC,0,Op,0,,phsA,,BOOLEAN,,,,44,P1 +BCU,None,1,MR.PAP1.PHASE *,X,Other,Positive or Rising,8,N/A,LDPAP,,PTRC,0,Op,0,,phsB,,BOOLEAN,,,,45,P1 +BCU,None,1,MR.PAP1.PHASE *,X,Other,Positive or Rising,8,N/A,LDPAP,,PTRC,0,Op,0,,phsC,,BOOLEAN,,,,46,P1 +BCU,None,1,DT.PAP1.IR,,??,Other,NA,N/A,LDPAP,,PTOC,1,Op,0,,general,,BOOLEAN,,,,47,P1 +BCU,None,1,REC.TDPAP1,X,Other,Positive or Rising,8,N/A,LDTDEC,,PSCH,0,RxTr,0,,general,,BOOLEAN,,,,48,P0 +BCU,None,1,EMI.TDPAP1,,??,Other,NA,N/A,LDTDEC,,PSCH,0,TxTr,0,,general,,BOOLEAN,,,,49,P0 +BCU,None,1,MR.PAP2,X,Other,Positive or Rising,8,N/A,LDPAP,,PTRC,0,Str,0,,general,,BOOLEAN,,,,50,P0 +BCU,None,1,DT.PAP2,,??,Other,NA,N/A,LDPAP,,PTRC,0,Op,0,,general,,BOOLEAN,,,,51,P0 +BCU,None,1,MR.PAP2.PHASE *,X,Other,Positive or Rising,8,N/A,LDPAP,,PTRC,0,Op,0,,phsA,,BOOLEAN,,,,52,P1 +BCU,None,1,MR.PAP2.PHASE *,X,Other,Positive or Rising,8,N/A,LDPAP,,PTRC,0,Op,0,,phsB,,BOOLEAN,,,,53,P1 +BCU,None,1,MR.PAP2.PHASE *,X,Other,Positive or Rising,8,N/A,LDPAP,,PTRC,0,Op,0,,phsC,,BOOLEAN,,,,54,P1 +BCU,None,1,DT.PAP2.IR,,??,Other,NA,N/A,LDPAP,,PTOC,1,Op,0,,general,,BOOLEAN,,,,55,P1 +PDL1,None,1,MR.PDL1,X,Other,Positive or Rising,8,N/A,LDDIFL,,PTRC,0,Str,0,,general,,BOOLEAN,,,,56,P1 +PDL1,None,1,DT.PDL1,,??,Other,NA,N/A,LDDIFL,,PTRC,0,Op,0,,general,,BOOLEAN,,,,57,P0 +PDL1,None,1,MR.PDL1.PHASE *,,??,Other,NA,N/A,LDDIFL,,PTRC,0,Str,0,,phsA,,BOOLEAN,,,,58,P0 +PDL1,None,1,MR.PDL1.PHASE *,,??,Other,NA,N/A,LDDIFL,,PTRC,0,Str,0,,phsB,,BOOLEAN,,,,59,P0 +PDL1,None,1,MR.PDL1.PHASE *,,??,Other,NA,N/A,LDDIFL,,PTRC,0,Str,0,,phsC,,BOOLEAN,,,,60,P0 +PDL2,None,1,MR.PDL2,X,Other,Positive or Rising,8,N/A,LDDIFL,,PTRC,0,Str,0,,general,,BOOLEAN,,,,61,P1 +PDL2,None,1,DT.PDL2,,??,Other,NA,N/A,LDDIFL,,PTRC,0,Op,0,,general,,BOOLEAN,,,,62,P0 +PDL2,None,1,MR.PDL2.PHASE *,X,Other,Positive or Rising,8,N/A,LDDIFL,,PTRC,0,Str,0,,phsA,,BOOLEAN,,,,63,P0 +PDL2,None,1,MR.PDL2.PHASE *,X,Other,Positive or Rising,8,N/A,LDDIFL,,PTRC,0,Str,0,,phsB,,BOOLEAN,,,,64,P0 +PDL2,None,1,MR.PDL2.PHASE *,X,Other,Positive or Rising,8,N/A,LDDIFL,,PTRC,0,Str,0,,phsC,,BOOLEAN,,,,65,P0 +PDB,None,1,MR.PDB,X,Other,Positive or Rising,8,N/A,LDPDB,,PTRC,0,Str,0,,general,,BOOLEAN,,,,66,P0 +PDB,None,1,DT.PDB,,??,Other,NA,N/A,LDPDB,,PTRC,0,Op,0,,general,,BOOLEAN,,,,67,P0 +PDB,None,1,MR.PDB.PHASE *,,??,Other,NA,N/A,LDPDB,,PTRC,0,Str,0,,phsA,,BOOLEAN,,,,68,P1 +PDB,None,1,MR.PDB.PHASE *,,??,Other,NA,N/A,LDPDB,,PTRC,0,Str,0,,phsB,,BOOLEAN,,,,69,P1 +PDB,None,1,MR.PDB.PHASE *,,??,Other,NA,N/A,LDPDB,,PTRC,0,Str,0,,phsC,,BOOLEAN,,,,70,P1 +BCU,None,1,MR.PMC1,X,Other,Positive or Rising,8,N/A,LDPMC,,PTRC,0,Str,0,,general,,BOOLEAN,,,,71,P0 +BCU,None,1,DT.PMC1,,??,Other,NA,N/A,LDPMC,,PTRC,0,Op,0,,general,,BOOLEAN,,,,72,P0 +BCU,None,1,MR.PMC2,X,Other,Positive or Rising,8,N/A,LDPMC,,PTRC,0,Str,0,,general,,BOOLEAN,,,,73,P0 +BCU,None,1,DT.PMC2,,??,Other,NA,N/A,LDPMC,,PTRC,0,Op,0,,general,,BOOLEAN,,,,74,P0 +BCU,None,1,MR.PMC2,X,Other,Positive or Rising,8,N/A,LDPMC,,PTRC,0,Str,0,,general,,BOOLEAN,,,,75,P0 +BCU,None,1,DT.PMC2,,??,Other,NA,N/A,LDPMC,,PTRC,0,Op,0,,general,,BOOLEAN,,,,76,P0 +CFD,None,1,DET.OPT.DEF.CAB1,X,Other,Positive or Rising,8,N/A,LDDFU,,PSCH,0,Op,0,,general,,BOOLEAN,,,,77,P0 +CFD,None,1,DET.OPT.DEF.CAB2,X,Other,Positive or Rising,8,N/A,LDDFU,,PSCH,0,Op,0,,general,,BOOLEAN,,,,78,P0 +CFD,None,1,DET.OPT.DEF.CAB3,X,Other,Positive or Rising,8,N/A,LDDFU,,PSCH,0,Op,0,,general,,BOOLEAN,,,,79,P0 +BCU,None,1,DT.MAXIL1,,??,Other,NA,N/A,LDMAXIL,,PTRC,0,Op,0,,general,,BOOLEAN,,,,80,P0 +BCU,None,1,MR.MAXIL1,X,Other,Positive or Rising,8,N/A,LDMAXIL,,PTRC,0,Str,0,,general,,BOOLEAN,,,,81,P1 +BCU,None,1,MR.MAXIL1.S1P,X,Other,Positive or Rising,8,N/A,LDMAXIL,,PTOC,1,Str,0,,general,,BOOLEAN,,,,82,P0 +BCU,None,1,MR.MAXIL1.S1T,X,Other,Positive or Rising,8,N/A,LDMAXIL,,PTOC,2,Str,0,,general,,BOOLEAN,,,,83,P0 +BCU,None,1,MR.MAXIL1.S2P,X,Other,Positive or Rising,8,N/A,LDMAXIL,,PTOC,3,Str,0,,general,,BOOLEAN,,,,84,P0 +BCU,None,1,DT.MAXIL2,,??,Other,NA,N/A,LDMAXIL,,PTRC,0,Op,0,,general,,BOOLEAN,,,,85,P0 +BCU,None,1,MR.MAXIL2,X,Other,Positive or Rising,8,N/A,LDMAXIL,,PTRC,0,Str,0,,general,,BOOLEAN,,,,86,P1 +BCU,None,1,MR.MAXIL2.S1P,X,Other,Positive or Rising,8,N/A,LDMAXIL,,PTOC,1,Str,0,,general,,BOOLEAN,,,,87,P0 +BCU,None,1,MR.MAXIL2.S1T,X,Other,Positive or Rising,8,N/A,LDMAXIL,,PTOC,2,Str,0,,general,,BOOLEAN,,,,88,P0 +BCU,None,1,MR.MAXIL2.S2P,X,Other,Positive or Rising,8,N/A,LDMAXIL,,PTOC,3,Str,0,,general,,BOOLEAN,,,,89,P0 +BCU,None,1,ADD.DEFAIL.DJ,X,Other,Positive or Rising,8,N/A,LDADD,,RBRF,0,OpEx,0,,general,,BOOLEAN,,,,90,P0 +AUT,None,1,,X,Other,Positive or Rising,8,N/A,,,,,,,,,,,,,,91,P0 +BCU,None,1,AR.ENCLT.RM,X,Other,Positive or Rising,8,N/A,LDREC,,RREC,1,OpCls,0,,general,,BOOLEAN,,,,92,P1 +BCU,None,1,AR.ENCLT.RTR,X,Other,Positive or Rising,8,N/A,LDREC,,RREC,2,OpCls,0,,general,,BOOLEAN,,,,93,P1 +BCU,None,1,AR.ENCLT.TAM,X,Other,Positive or Rising,8,N/A,LDREC,,RREC,3,OpCls,0,,general,,BOOLEAN,,,,94,P1 +BCU,None,1,AR.ENCLT.REBTAM,X,Other,Positive or Rising,8,N/A,LDREC,,RREC,4,OpCls,0,,general,,BOOLEAN,,,,95,P1 +BCU,None,1,AR.ENCLT.RT,X,Other,Positive or Rising,8,N/A,LDRS,,RREC,0,OpCls,0,,general,,BOOLEAN,,,,96,P1 +BCU,None,1,AR.ENCLT.RTS,X,Other,Positive or Rising,8,N/A,LDRTS,,RREC,0,OpCls,0,,general,,BOOLEAN,,,,97,P1 +BCU,None,1,AR.ENCLT.RTS,X,Other,Positive or Rising,8,N/A,LDAMU,,RREC,0,OpCls,0,,general,,BOOLEAN,,,,98,P1 +AUT,None,1,AR.ENCLT,X ,Other,Positive or Rising,8,N/A,LDGRP,,,,,,,,,,,,,99,P0 +BCU,None,1,BCU.FERM.DJ,X,Other,Positive or Rising,8,N/A,LDCMDDJ,,CSWI,1,OpCls,0,,general,,BOOLEAN,,,,100,P1 +BCU,None,1,BCU.OUVERT.DJ,X,Other,Positive or Rising,8,N/A,LDCMDDJ,,CSWI,1,OpOpn,0,,general,,BOOLEAN,,,,101,P1 +SCU-ORG,A,1,SCU.OUV.DJ,X,Other,Positive or Rising,8,N/A,LDDJ,,XCMD,0,OpOpn,0,,general,,BOOLEAN,,,,102,P0 +SCU-ORG,A,1,SCU.FERM.DJ,X,Other,Positive or Rising,8,N/A,LDDJ,,XCMD,0,OpCls,0,,general,,BOOLEAN,,,,103,P0 +BCU,None,1,DPHILB,,??,Other,NA,N/A,LDCMDDJ,,RSYN,1,AngInd,0,,stVal,,BOOLEAN,,,,104,P0 +BCU,None,1,DFLB,,??,Other,NA,N/A,LDCMDDJ,,RSYN,1,HzInd,0,,stVal,,BOOLEAN,,,,105,P0 +BCU,None,1,DULB,,??,Other,NA,N/A,LDCMDDJ,,RSYN,1,VInd,0,,stVal,,BOOLEAN,,,,106,P0 +BCU,None,1,PUL,,??,Other,NA,N/A,LDCMDDJ,,FXOT,1,Op,0,,general,,BOOLEAN,,,,107,P0 +BCU,None,1,PUB,,??,Other,NA,N/A,LDCMDDJ,,FXOT,2,Op,0,,general,,BOOLEAN,,,,108,P0 +BCU,None,1,AUL,,??,Other,NA,N/A,LDCMDDJ,,FXUT,1,Op,0,,general,,BOOLEAN,,,,109,P0 +BCU,None,1,AUB,,??,Other,NA,N/A,LDCMDDJ,,FXUT,2,Op,0,,general,,BOOLEAN,,,,110,P0 +BCU,None,1,CYCLE.ARS.ACTIF,,??,Other,NA,N/A,,,,,,,,,,,,,,111,P1 +BCU,None,1,MQ.U.102,X,??,Other,NA,N/A,LDMQUB1,CB00001002,FXUT,0,Op,0,,general,,BOOLEAN,,,,112,P0 +BCU,None,1,MQ.U.103,X,??,Other,NA,N/A,LDMQUB1,CB00001003,FXUT,0,Op,0,,general,,BOOLEAN,,,,113,P0 +BCU,None,1,MQ.U.104,X,??,Other,NA,N/A,LDMQUB1,CB00001004,FXUT,0,Op,0,,general,,BOOLEAN,,,,114,P0 +BCU,None,1,MQ.U.105,X,??,Other,NA,N/A,LDMQUB1,CB00001005,FXUT,0,Op,0,,general,,BOOLEAN,,,,115,P1 +BCU,None,1,MQ.U.106,X,??,Other,NA,N/A,LDMQUB1,CB00001006,FXUT,0,Op,0,,general,,BOOLEAN,,,,116,P1 +BCU,None,1,MQ.U.202,X,??,Other,NA,N/A,LDMQUB1,CB00002002,FXUT,0,Op,0,,general,,BOOLEAN,,,,117,P1 +BCU,None,1,MQ.U.101,X,??,Other,NA,N/A,LDMQUB1,CB00001001,FXUT,0,Op,0,,general,,BOOLEAN,,,,118,P0 +BCU,None,1,MQ.U.201,X,Other,Positive or Rising,8,N/A,LDMQUB1,CB00002001,FXUT,0,Op,0,,general,,BOOLEAN,,,,119,P0 +BCU,None,1,REC.TDECx.Vy,X,Other,Positive or Rising,8,N/A,LDTDEC,,PSCH,0,RxTr,0,,general,,BOOLEAN,,,,120,P0 +BCU,None,1,EMI.TDECx.Vy,,??,Other,NA,N/A,LDTDEC,,PSCH,0,TxTr,0,,general,,BOOLEAN,,,,121,P0 +BCU,None,1,REC.DESARM.ARS,X,Other,Positive or Rising,8,N/A,LDTDEC,,PSCH,0,RxTr,0,,general,,BOOLEAN,,,,122,P0 +BCU,None,1,EMI.TDECx.Vy,,??,Other,NA,N/A,LDTDEC,,PSCH,0,TxTr,0,,general,,BOOLEAN,,,,123,P0 +BCU,None,1,DT.TDEC,,??,Other,NA,N/A,LDTDEC,,PTRC,0,Op,0,,general,,BOOLEAN,,,,124,P1 +BCU,None,1,EPS.MER,X,Other,Positive or Rising,8,N/A,LDEPS,,RDRE,1,RcdStr,0,,stVal,,BOOLEAN,,,,125,P0 +BCU,None,1,PO.MER,X,Other,Positive or Rising,8,N/A,LDEPF,,RDRE,2,RcdTrg,0,,stVal,,BOOLEAN,,,,126,P0 +BCU,None,1,PRS.MER,X,Other,Positive or Rising,8,N/A,LDPRS,,PTRC,0,Str,0,,general,,BOOLEAN,,,,127,P0 +BCU,None,1,DT.PRS,,??,Other,NA,N/A,LDPRS,,PTRC,0,Op,0,,general,,BOOLEAN,,,,128,P0 +BCU,None,1,ANO.TCT.L,X,Other,Positive or Rising,8,N/A,LDSUTCT,,CALH,1,GrInd,0,,stVal,,BOOLEAN,,,,129,P0 +BCU,None,1,ANO.TCT.B,X,Other,Positive or Rising,8,N/A,LDSUTCT,,CALH,2,GrInd,0,,stVal,,BOOLEAN,,,,130,P0 +BCU,None,1,DT.SUTCT,,??,Other,NA,N/A,LDSUTCT,,PTRC,0,Op,0,,general,,BOOLEAN,,,,131,P0 +BCU,None,1,MR.PSPT,X,Other,Positive or Rising,8,N/A,LDPSPT,,PTRC,0,Str,0,,general,,BOOLEAN,,,,132,P0 +BCU,None,1,DT.PSPT,,??,Other,NA,N/A,LDPSPT,,PTRC,0,Op,0,,general,,BOOLEAN,,,,133,P0 +PDT,None,1,MR.PDT,X,Other,Positive or Rising,8,N/A,LDPDT,,PTRC,0,Str,0,,general,,BOOLEAN,,,,134,P0 +PDT,None,1,DT.PDT,,??,Other,NA,N/A,LDPDT,,PTRC,0,Op,0,,general,,BOOLEAN,,,,135,P0 +PTP,None,1,MR.PTP,X,Other,Positive or Rising,8,N/A,LDPTP,,PTRC,0,Str,0,,general,,BOOLEAN,,,,136,P0 +PTP,None,1,DT.PTP ,,??,Other,NA,N/A,LDPTP,,PTRC,0,Op,0,,general,,BOOLEAN,,,,137,P0 +PDB,None,1,MR.PDLP,X,Other,Positive or Rising,8,N/A,LDPTLP,,PTRC,0,Str,0,,general,,BOOLEAN,,,,138,P0 +PDB,None,1,DT.PDLP,,??,Other,NA,N/A,LDPDLP,,PTRC,0,Op,0,,general,,BOOLEAN,,,,139,P0 +PDB,None,1,MR.PDLC,X,Other,Positive or Rising,8,N/A,LDPDLC,,PTRC,0,Str,0,,general,,BOOLEAN,,,,140,P0 +PDB,None,1,DT.PDLC,,??,Other,NA,N/A,LDPDLC,,PTRC,0,Op,0,,general,,BOOLEAN,,,,141,P0 +BCU,None,1,MR.MAXUL,X,Other,Positive or Rising,8,N/A,LDMAXU,,PTRC,0,Str,0,,general,,BOOLEAN,,,,142,P0 +BCU,None,1,DT.MAXUL,,??,Other,NA,N/A,LDMAXU,,PTRC,0,Op,0,,general,,BOOLEAN,,,,143,P0 +SAMU,A,1,V0,,NA,NA,8,N/A,LDTM1,U01A,TVTR,11,VolSv,0,,instMag,,AnalogueValue,i,,1,,P0 +SAMU,A,1,V4,,NA,NA,8,N/A,LDTM1,U01B,TVTR,12,VolSv,0,,instMag,,AnalogueValue,i,,2,,P0 +SAMU,A,1,V8,,NA,NA,8,N/A,LDTM1,U01C,TVTR,13,VolSv,0,,instMag,,AnalogueValue,i,,3,,P0 +SAMU,A,1,J0,,NA,NA,8,N/A,LDTM1,I01A,TCTR,11,AmpSv,0,,instMag,,AnalogueValue,i,,4,,P0 +SAMU,A,1,J4,,NA,NA,8,N/A,LDTM1,I01B,TCTR,12,AmpSv,0,,instMag,,AnalogueValue,i,,5,,P0 +SAMU,A,1,.J8,,NA,NA,8,N/A,LDTM1,J01C,TCTR,13,AmpSv,0,,instMag,,AnalogueValue,i,,6,,P0 +SAMU,A,1,I0,,NA,NA,8,N/A,LDTM1,I05A,TCTR,51,AmpSv,0,,instMag,,AnalogueValue,i,,7,,P0 +SAMU,A,1,I4,,NA,NA,8,N/A,LDTM1,I05B,TCTR,52,AmpSv,0,,instMag,,AnalogueValue,i,,8,,P0 +SAMU,A,1,I8,,NA,NA,8,N/A,LDTM1,I05C,TCTR,53,AmpSv,0,,instMag,,AnalogueValue,i,,9,,P0 +SAMU,A,1,G,,NA,NA,8,N/A,LDTM1,I06N,TCTR,61,AmpSv,0,,instMag,,AnalogueValue,i,,16,,P0 +SAMU,A,1,U101,,NA,NA,8,N/A,LDPHAS1,,MMXU,101,PhV,0,phsA;phsB;phsC,cVal,,AnalogueValue,mag,f,10,,P0 +SAMU,A,1,U102,,NA,NA,8,N/A,LDPHAS1,,MMXU,102,PhV,0,phsA;phsB;phsC,cVal,,AnalogueValue,mag,f,11,,P0 +SAMU,A,1,U103,,NA,NA,8,N/A,LDPHAS1,,MMXU,103,PhV,0,phsA;phsB;phsC,cVal,,AnalogueValue,mag,f,12,,P0 +SAMU,A,1,U104,,NA,NA,8,N/A,LDPHAS1,,MMXU,104,PhV,0,phsA;phsB;phsC,cVal,,AnalogueValue,mag,f,13,,P0 +SAMU,A,1,U105,,NA,NA,8,N/A,LDPHAS1,,MMXU,105,PhV,0,phsA;phsB;phsC,cVal,,AnalogueValue,mag,f,14,,P0 +SAMU,A,1,U106,,NA,NA,8,N/A,LDPHAS1,,MMXU,106,PhV,0,phsA;phsB;phsC,cVal,,AnalogueValue,mag,f,15,,P0 +SAMU,A,1,U201,,NA,NA,8,N/A,LDPHAS1,,MMXU,201,PhV,0,phsA;phsB;phsC,cVal,,AnalogueValue,mag,f,14,,P0 +SAMU,A,1,U202,,NA,NA,8,N/A,LDPHAS1,,MMXU,202,PhV,0,phsA;phsB;phsC,cVal,,AnalogueValue,mag,f,15,,P0 diff --git a/sct-commons/src/test/resources/monitoring_lns/scd_monitoring_lsvs_lgos.xml b/sct-commons/src/test/resources/monitoring_lns/scd_monitoring_lsvs_lgos.xml new file mode 100644 index 000000000..35f8d82c3 --- /dev/null +++ b/sct-commons/src/test/resources/monitoring_lns/scd_monitoring_lsvs_lgos.xml @@ -0,0 +1,128 @@ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sct-commons/src/test/resources/scd-test-update-inref/scd_update_inref_issue_231_test_ok.xml b/sct-commons/src/test/resources/scd-test-update-inref/scd_update_inref_issue_231_test_ok.xml index fbbbd0dfd..638411315 100644 --- a/sct-commons/src/test/resources/scd-test-update-inref/scd_update_inref_issue_231_test_ok.xml +++ b/sct-commons/src/test/resources/scd-test-update-inref/scd_update_inref_issue_231_test_ok.xml @@ -17,8 +17,8 @@ LD_WITH_1_InRef_DOI_InRef2 - - + + OLD_VAL @@ -41,11 +41,11 @@ LD_WITH_3_InRef_DOI_InRef3 - + OLD_VAL - - + + OLD_VAL @@ -138,6 +138,7 @@ + @@ -146,10 +147,10 @@ - - - - + + + + diff --git a/sct-commons/src/test/resources/scd-test-update-inref/scd_update_inref_test.xml b/sct-commons/src/test/resources/scd-test-update-inref/scd_update_inref_test.xml index 3a26f7493..8cc947077 100644 --- a/sct-commons/src/test/resources/scd-test-update-inref/scd_update_inref_test.xml +++ b/sct-commons/src/test/resources/scd-test-update-inref/scd_update_inref_test.xml @@ -27,7 +27,7 @@ LD_WITH_1_InRef_DOI_InRef2 - + OLD_VAL @@ -51,11 +51,11 @@ LD_WITH_3_InRef_DOI_InRef3 - + OLD_VAL - - + + OLD_VAL @@ -132,12 +132,12 @@ LD_WITH_1_InRef_without_cbName_DOI_InRef7 - + OLD_VAL - - + + - + + + + + + + + - - - - - - - - + + + + + + \ No newline at end of file