From c29432e43dc84381b0ad81e1b2ba6cb8a67afb82 Mon Sep 17 00:00:00 2001 From: slacourte Date: Thu, 15 Jan 2026 15:42:04 +0100 Subject: [PATCH] M&C testbed. --- .../org/ccsds/moims/mo/mc/ActionDataset.java | 109 ++ .../ccsds/moims/mo/mc/AggregationDataset.java | 170 +++ .../org/ccsds/moims/mo/mc/AlertDataset.java | 119 ++ .../ccsds/moims/mo/mc/MCServicesFactory.java | 3 +- .../org/ccsds/moims/mo/mc/PacketDataset.java | 104 ++ .../ccsds/moims/mo/mc/ParameterDataset.java | 241 ++++ .../moims/mo/mc/backends/ActionBackend.java | 53 + .../mo/mc/backends/AggregationBackend.java | 126 ++ .../moims/mo/mc/backends/AlertBackend.java | 49 + .../moims/mo/mc/backends/BackendTimer.java | 75 ++ .../mo/mc/backends/ConversionFunction.java | 46 + .../moims/mo/mc/backends/PacketBackend.java | 62 + .../mo/mc/backends/ParameterBackend.java | 122 +- .../AggregationProviderServiceImpl.java | 6 +- .../mc/util/ESAMCServicesFactory.java | 5 +- .../cnes-rmi/LocalMALInstanceMAL.properties | 22 + .../TestServiceProviderMAL.properties | 22 + .../resources/deployment/cnes-rmi/a3debug.cfg | 66 + testbeds/testbed-mc/logging.properties | 2 + testbeds/testbed-mc/pom.xml | 6 +- .../org/ccsds/mo/mc/testbed/Constant.java | 117 ++ .../testbed/SetUpProvidersAndConsumers.java | 123 +- .../testbed/backends/ActionBasicDataset.java | 90 ++ .../backends/ActionDefaultDataset.java | 300 +++++ .../backends/AggregationBasicDataset.java | 96 ++ .../AggregationDatasetForReportConfig.java | 127 ++ .../backends/AggregationDefaultDataset.java | 96 ++ .../backends/AggregationDynamicDataset.java | 98 ++ .../backends/AggregationErrorDataset.java | 163 +++ .../testbed/backends/AlertBasicDataset.java | 87 ++ .../testbed/backends/AlertDefaultDataset.java | 109 ++ .../testbed/backends/AlertErrorDataset.java | 110 ++ .../mc/testbed/backends/BackendTimerImpl.java | 209 +++ .../backends/FifteenProductsDataset.java | 57 - ...ctDataset.java => PacketBasicDataset.java} | 43 +- .../backends/ParameterBasicDataset.java | 101 ++ .../ParameterDatasetForReportConfig.java | 60 + .../ParameterDatasetForValidityState.java | 93 ++ .../backends/ParameterDefaultDataset.java | 190 +++ .../backends/ParameterErrorDataset.java | 169 +++ .../mo/mc/testbed/backends/package-info.java | 5 +- .../org/ccsds/mo/mc/testbed/package-info.java | 2 +- .../mc/testbed/AC_1_Basic_Execution_Test.java | 103 ++ .../mc/testbed/AC_2_Basic_Monitor_Test.java | 168 +++ .../testbed/AC_3_Extended_Execution_Test.java | 273 ++++ .../AC_4_Extended_Monitoring_Test.java | 499 +++++++ .../testbed/AC_5_Special_Monitoring_Test.java | 231 ++++ .../mc/testbed/AC_9_Execution_Error_Test.java | 445 +++++++ .../ccsds/mo/mc/testbed/AG_1_Basic_Test.java | 223 ++++ .../mc/testbed/AG_2_Nominal_Values_Test.java | 331 +++++ .../mc/testbed/AG_3_Report_Config_Test.java | 866 ++++++++++++ .../mo/mc/testbed/AG_4_Dynamic_Test.java | 603 +++++++++ .../ccsds/mo/mc/testbed/AG_9_Errors_Test.java | 835 ++++++++++++ .../ccsds/mo/mc/testbed/AL_1_Basic_Test.java | 171 +++ .../mo/mc/testbed/AL_2_Generation_Test.java | 434 ++++++ .../ccsds/mo/mc/testbed/AL_9_Errors_Test.java | 236 ++++ .../ccsds/mo/mc/testbed/ActionListener.java | 235 ++++ .../ccsds/mo/mc/testbed/ActionTestClient.java | 297 +++++ .../mo/mc/testbed/AggregationListener.java | 438 ++++++ .../mo/mc/testbed/AggregationTestClient.java | 1179 +++++++++++++++++ .../ccsds/mo/mc/testbed/AlertListener.java | 245 ++++ .../ccsds/mo/mc/testbed/AlertTestClient.java | 520 ++++++++ .../java/org/ccsds/mo/mc/testbed/MCTest.java | 670 +++++++++- .../ccsds/mo/mc/testbed/PA_1_Basic_Test.java | 255 ++++ .../mc/testbed/PA_2_Nominal_Values_Test.java | 375 ++++++ .../mc/testbed/PA_3_Report_Config_Test.java | 751 +++++++++++ .../mc/testbed/PA_4_Validity_State_Test.java | 428 ++++++ .../ccsds/mo/mc/testbed/PA_9_Errors_Test.java | 522 ++++++++ .../ccsds/mo/mc/testbed/PK_1_Basic_Test.java | 168 +++ .../mo/mc/testbed/PK_2_Extended_Test.java | 381 ++++++ .../ccsds/mo/mc/testbed/PacketListener.java | 181 +++ .../ccsds/mo/mc/testbed/PacketTestClient.java | 230 ++++ .../mo/mc/testbed/ParameterListener.java | 383 ++++++ .../mo/mc/testbed/ParameterTestClient.java | 904 +++++++++++++ .../ccsds/mo/mc/testbed/TestDependency.java | 73 + .../org/ccsds/mo/mc/testbed/UC1_Ex1_Test.java | 66 - .../src/main/resources/MCPrototype.xml | 5 +- .../xml/area004-v002-Monitor-and-Control.xml | 987 ++++++++++++++ 78 files changed, 18336 insertions(+), 228 deletions(-) create mode 100755 apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/ActionDataset.java create mode 100755 apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/AggregationDataset.java create mode 100755 apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/AlertDataset.java create mode 100755 apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/PacketDataset.java create mode 100755 apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/AggregationBackend.java create mode 100755 apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/BackendTimer.java create mode 100755 apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ConversionFunction.java create mode 100755 testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/LocalMALInstanceMAL.properties create mode 100755 testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/TestServiceProviderMAL.properties create mode 100755 testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/a3debug.cfg create mode 100755 testbeds/testbed-mc/logging.properties create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/Constant.java create mode 100644 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ActionBasicDataset.java create mode 100644 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ActionDefaultDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationBasicDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDatasetForReportConfig.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDefaultDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDynamicDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationErrorDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertBasicDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertDefaultDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertErrorDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/BackendTimerImpl.java delete mode 100644 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/FifteenProductsDataset.java rename testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/{OneProductDataset.java => PacketBasicDataset.java} (50%) mode change 100644 => 100755 create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterBasicDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDatasetForReportConfig.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDatasetForValidityState.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDefaultDataset.java create mode 100755 testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterErrorDataset.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_1_Basic_Execution_Test.java create mode 100644 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_2_Basic_Monitor_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_3_Extended_Execution_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_4_Extended_Monitoring_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_5_Special_Monitoring_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_9_Execution_Error_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_1_Basic_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_2_Nominal_Values_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_3_Report_Config_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_4_Dynamic_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_9_Errors_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_1_Basic_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_2_Generation_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_9_Errors_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ActionListener.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ActionTestClient.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AggregationListener.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AggregationTestClient.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AlertListener.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AlertTestClient.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_1_Basic_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_2_Nominal_Values_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_3_Report_Config_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_4_Validity_State_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_9_Errors_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PK_1_Basic_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PK_2_Extended_Test.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PacketListener.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PacketTestClient.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ParameterListener.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ParameterTestClient.java create mode 100755 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/TestDependency.java delete mode 100644 testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/UC1_Ex1_Test.java create mode 100755 xml-service-specifications/xml-ccsds-mo-standards/src/main/resources/xml/area004-v002-Monitor-and-Control.xml diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/ActionDataset.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/ActionDataset.java new file mode 100755 index 000000000..3790c6e17 --- /dev/null +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/ActionDataset.java @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : ESA CCSDS MO Services + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.moims.mo.mc; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mc.backends.ActionBackend; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ActionDefinition; +import org.ccsds.moims.mo.mc.structures.ActionDefinitionList; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; + +/** + * A abstract class for all backend Action Datasets + */ +public abstract class ActionDataset implements ActionBackend { + + /** class logger */ + private static final Logger logger = Logger.getLogger(ActionDataset.class.getName()); + /** List of ActionDefinition objects known to the provider. */ + private final ActionDefinitionList definitions = new ActionDefinitionList(); + + @Override + public ActionDefinitionList getAllActionDefinitions() { + return definitions; + } + + /** + * Adds an ActionDefinition object to the list handled by the provider. + * This method is expected to be called by the specific test backend, at initialization time. + * + * @param identity field of the ActionDefinition to create + * @param description field of the ActionDefinition to create + * @param category field of the ActionDefinition to create + * @param progressStepCount field of the ActionDefinition to create + * @param arguments field of the ActionDefinition to create + */ + protected void addAction( + ObjectIdentity identity, + String description, + ActionCategory category, + UShort progressStepCount, + ArgumentDefinitionList arguments) { + ActionDefinition definition = + new ActionDefinition(identity, description, category, progressStepCount, arguments); + if (!definitions.add(definition)) { + IllegalArgumentException exc = new IllegalArgumentException( + "cannot add the ActionDefinition object to the list"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + } + + @Override + public String check( + ActionExecutionRequest executionRequest, + ActionDefinition definition) { + // to be overloaded in derived classes + logger.info("backend check return null"); + return null; + } + + @Override + public boolean execute( + ActionExecutionRequest executionRequest, + ActionDefinition definition, + ExecuteListener listener) { + int progressStepCount = definition.getProgressStepCount().getValue(); + if (progressStepCount == 0) { + logger.info("backend execute return true"); + return true; + } + if (listener == null) { + logger.info("backend execute return false"); + return false; + } + for (int i=0; iAggregationDefinition objects known to the provider. + * The index of an object in this list is used as an identifier. + * Objects should never be deleted from this list. + */ + private final AggregationDefinitionList definitions = new AggregationDefinitionList(); + /** List of default report configuration, matching the definitions in the {@link definitions} list. */ + private final List defaultConfigs = new Vector<>(); + /** Default report configuration for all supplementary Aggregations of the provider. */ + private DefaultReportConfiguration defaultSupplementaryConfig; + /** Connection details to the Parameter provider */ + protected final SingleConnectionDetails parameterConnectionDetails; + /** Backend timer to use by the provider, for time related operations */ + protected final BackendTimer timer; + + /** + * Constructor with required parameters. + * + * @param timer Backend timer to use by the provider + * @param parameterConnectionDetails Connection details to the Parameter provider + */ + public AggregationDataset( + BackendTimer timer, + SingleConnectionDetails parameterConnectionDetails) { + this.timer = timer; + this.parameterConnectionDetails = parameterConnectionDetails; + } + + @Override + public BackendTimer getTimer() { + return timer; + } + + @Override + public AggregationDefinitionList getAllAggregationDefinitions() { + return definitions; + } + + @Override + public DefaultReportConfiguration getDefaultReportConfig(int aggregationID) { + if (aggregationID >= defaultConfigs.size()) { + return defaultSupplementaryConfig; + } + return defaultConfigs.get(aggregationID); + } + + @Override + public DefaultReportConfiguration getDefaultReportConfig() { + return defaultSupplementaryConfig; + } + + @Override + public IdentifierList getCategories() { + return null; + } + + @Override + public SingleConnectionDetails getParameterConnectionDetails() { + return parameterConnectionDetails; + } + + /** + * Adds an AggregationDefinition object to the list handled by the provider. + * This function is expected to be called by the specific test backend, at initialization time. + * + * @param identity field of the AggregationDefinition to create + * @param description field of the AggregationDefinition to create + * @param category field of the AggregationDefinition to create + * @param parameters field of the AggregationDefinition to create + * @param config default configuration of the AggregationDefinition to create + * @return identifier of the object + */ + protected int addAggregation( + ObjectIdentity identity, + String description, + Identifier category, + ObjectRefList parameters, + DefaultReportConfiguration config) { + AggregationDefinition definition = + new AggregationDefinition(identity, description, category, parameters); + if (!definitions.add(definition)) { + IllegalArgumentException exc = new IllegalArgumentException( + "cannot add the AggregationDefinition object to the list"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + int aggregationID = definitions.size()-1; + logger.info("aggregation " + aggregationID + " added: " + definition); + if (!defaultConfigs.add(config)) { + IllegalArgumentException exc = new IllegalArgumentException( + "cannot add the default configuration to the list"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + return aggregationID; + } + + /** + * Defines the default reporting configuration for supplementary Aggregations. + * + * @param defaultSupplementaryConfig default reporting configuration + */ + protected void addDefaultReportConfig(DefaultReportConfiguration defaultSupplementaryConfig) { + this.defaultSupplementaryConfig = defaultSupplementaryConfig; + } + + public static final Identifier INVALID_ID = new Identifier("INVALID_ID"); + @Override + public boolean isValidId(IdentifierList domain, Identifier key) { + if (domain == null) + return false; + if (key == null) + return false; + for (int i = 0; i < domain.size(); i++) { + if ("".equals(domain.get(i)) || + "*".equals(domain.get(i))) + return false; + } + if (INVALID_ID.equals(key)) + return false; + return true; + } +} diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/AlertDataset.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/AlertDataset.java new file mode 100755 index 000000000..e4d8e2d74 --- /dev/null +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/AlertDataset.java @@ -0,0 +1,119 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : ESA CCSDS MO Services + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.moims.mo.mc; + +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mc.backends.AlertBackend; +import org.ccsds.moims.mo.mc.structures.AlertDefinition; +import org.ccsds.moims.mo.mc.structures.AlertDefinitionList; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.Severity; + +/** + * A abstract class for all backend AlertDataset. + */ +public abstract class AlertDataset implements AlertBackend { + + /** class logger */ + private static final Logger logger = Logger.getLogger(AlertDataset.class.getName()); + + /** + * List of AlertDefinition objects known to the provider. + * The index of an object in this list is used as an identifier. + * Objects should never be deleted from this list. + */ + private final AlertDefinitionList definitions = new AlertDefinitionList(); + /** list of registered listeners to signal for condition values updates */ + private final Set listeners = new HashSet<>(); + + @Override + public AlertDefinitionList getAllAlertDefinitions() { + return definitions; + } + + /** + * Adds an AlertDefinition object to the list handled by the provider. + * This function is expected to be called by the specific test backend, at initialization time. + * + * @param identity field of the AlertDefinition to create + * @param description field of the AlertDefinition to create + * @param severity field of the AlertDefinition to create + * @param arguments field of the AlertDefinition to create + * @return identifier of the object + */ + protected int addAlert( + ObjectIdentity identity, + String description, + Severity severity, + ArgumentDefinitionList arguments) { + AlertDefinition definition = + new AlertDefinition(identity, description, severity, arguments); + if (!definitions.add(definition)) { + IllegalArgumentException exc = new IllegalArgumentException( + "cannot add the AlertDefinition object to the list"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + int alertID = definitions.size()-1; + logger.info("alert " + alertID + " added: " + definition); + return alertID; + } + + @Override + public void register(AlertListener listener) { + listeners.add(listener); + } + @Override + public void deregister(AlertListener listener) { + listeners.remove(listener); + } + + /** + * Reports the result of the evaluation of the condition of an Alert. + * The condition value is reported in the status parameter. + * When the condition value is true, then the values of the Alert arguments are provided + * in the arguments parameter. + * Notifies all listeners of the change. + * + * In the testbed, this method is expected to be called by the test clients. + * + * @param alertID identifier of the reported Alert + * @param status value of the Alert's condition + * @param arguments argument values of the Alert when status is true + */ + public void reportAlertCondition( + int alertID, + boolean status, + NullableAttributeList arguments) { + for (AlertListener listener : listeners) { + listener.notifyAlertCondition(alertID, status, arguments); + } + } +} diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/MCServicesFactory.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/MCServicesFactory.java index 2bd9218f7..d657b3dd3 100644 --- a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/MCServicesFactory.java +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/MCServicesFactory.java @@ -33,6 +33,7 @@ import org.ccsds.moims.mo.mc.parameter.consumer.ParameterStub; import org.ccsds.moims.mo.mc.parameter.provider.ParameterInheritanceSkeleton; import org.ccsds.moims.mo.mc.backends.ActionBackend; +import org.ccsds.moims.mo.mc.backends.AggregationBackend; import org.ccsds.moims.mo.mc.backends.AlertBackend; import org.ccsds.moims.mo.mc.backends.PacketBackend; import org.ccsds.moims.mo.mc.backends.ParameterBackend; @@ -44,7 +45,7 @@ public abstract class MCServicesFactory { public abstract ActionInheritanceSkeleton createProviderAction(ActionBackend backend) throws MALException; - public abstract AggregationInheritanceSkeleton createProviderAggregation(ParameterBackend backend) throws MALException; + public abstract AggregationInheritanceSkeleton createProviderAggregation(AggregationBackend backend) throws MALException; public abstract AlertInheritanceSkeleton createProviderAlert(AlertBackend backend) throws MALException; diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/PacketDataset.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/PacketDataset.java new file mode 100755 index 000000000..472d9c0a1 --- /dev/null +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/PacketDataset.java @@ -0,0 +1,104 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : ESA CCSDS MO Services + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.moims.mo.mc; + +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Logger; + +import org.ccsds.moims.mo.mal.structures.AttributeTypeList; +import org.ccsds.moims.mo.mal.structures.Blob; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mc.backends.PacketBackend; + +/** + * A abstract class for all backend PacketDataset. + */ +public abstract class PacketDataset implements PacketBackend { + + /** class logger */ + private static final Logger logger = Logger.getLogger(PacketDataset.class.getName()); + + /** Names of the custom subscription keys of the deliverPacket operation. */ + private IdentifierList customSubscriptionKeyNames; + /** Types of the custom subscription keys of the deliverPacket operation. */ + private AttributeTypeList customSubscriptionKeyTypes; + + @Override + public IdentifierList getCustomSubscriptionKeyNames() { + return customSubscriptionKeyNames; + } + @Override + public AttributeTypeList getCustomSubscriptionKeyTypes() { + return customSubscriptionKeyTypes; + } + + /** + * Defines the custom subscription keys of the deliverPacket operation. + * This method is expected to be called in the constructor of derived classes. + * + * @param customSubscriptionKeyNames names of the custom subscription keys + * @param customSubscriptionKeyTypes types of the custom subscription keys + */ + protected void setCustomSubscriptionKeys( + IdentifierList customSubscriptionKeyNames, + AttributeTypeList customSubscriptionKeyTypes) { + this.customSubscriptionKeyNames = customSubscriptionKeyNames; + this.customSubscriptionKeyTypes = customSubscriptionKeyTypes; + } + + /** list of registered listeners to signal for new packets */ + private final Set listeners = new HashSet<>(); + + @Override + public void register(PacketListener listener) { + listeners.add(listener); + } + @Override + public void deregister(PacketListener listener) { + listeners.remove(listener); + } + + /** + * Publishes a new Packet. Notifies all listeners. + * + * In the testbed, this method is expected to be called by the test clients. + * + * @param domain domain of the packet to publish + * @param keyValues values of all subscription keys, including the standard apid and the custom ones + * @param timestamp timestamp of the packet + * @param spacePacket body of the packet + */ + public void publishPacket( + IdentifierList domain, + NullableAttributeList keyValues, + Time timestamp, + Blob spacePacket) { + for (PacketListener listener : listeners) { + listener.notifyPacket(domain, keyValues, timestamp, spacePacket); + } + } +} diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/ParameterDataset.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/ParameterDataset.java index d1591b156..211a1f16b 100644 --- a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/ParameterDataset.java +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/ParameterDataset.java @@ -4,6 +4,9 @@ * Darmstadt * Germany * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- * System : ESA CCSDS MO Services * ---------------------------------------------------------------------------- * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 @@ -20,11 +23,249 @@ */ package org.ccsds.moims.mo.mc; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mc.backends.BackendTimer; +import org.ccsds.moims.mo.mc.backends.ConversionFunction; import org.ccsds.moims.mo.mc.backends.ParameterBackend; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterDefinitionList; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ValidityState; /** * A abstract class for all backend ParameterDataset. */ public abstract class ParameterDataset implements ParameterBackend { + /** class logger */ + private static final Logger logger = Logger.getLogger(ParameterDataset.class.getName()); + /** + * List of ParameterDefinition objects known to the provider. + * The index of an object in this list is used as an identifier. + * Objects should never be deleted from this list. + */ + private final ParameterDefinitionList definitions = new ParameterDefinitionList(); + /** List of read-only properties, matching the definitions in the {@link definitions} list. */ + private final List readOnlyProperties = new Vector<>(); + /** List of default report configurations, matching the definitions in the {@link definitions} list. */ + private final List defaultConfigs = new Vector<>(); + /** List of conversion functions, matching the definitions in the {@link definitions} list. */ + private final List conversionFunctions = new Vector<>(); + /** backend timer to use by the provider, for time related operations */ + protected final BackendTimer timer; + + public ParameterDataset(BackendTimer timer) { + this.timer = timer; + } + + @Override + public BackendTimer getTimer() { + return timer; + } + + @Override + public ParameterDefinitionList getAllParameterDefinitions() { + return definitions; + } + + @Override + public DefaultReportConfiguration getDefaultReportConfig(int parameterID) { + if (parameterID >= defaultConfigs.size()) { + IllegalArgumentException exc = new IllegalArgumentException("unknown ParameterDefinition id"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + return defaultConfigs.get(parameterID); + } + + /** + * Adds a ParameterDefinition object to the list handled by the provider. + * This function is expected to be called by the specific test backend, at initialization time. + * + * @param identity field of the ParameterDefinition to create + * @param description field of the ParameterDefinition to create + * @param rawType field of the ParameterDefinition to create + * @param rawUnit field of the ParameterDefinition to create + * @param convertedType field of the ParameterDefinition to create + * @param convertedUnit field of the ParameterDefinition to create + * @param config default configuration of the ParameterDefinition to create + * @param conversionFunction conversion function, may be null + * @param readOnly read-only property of the Parameter + * @return identifier of the object + */ + protected int addParameter( + ObjectIdentity identity, + String description, + AttributeType rawType, + String rawUnit, + AttributeType convertedType, + String convertedUnit, + DefaultReportConfiguration config, + ConversionFunction conversionFunction, + boolean readOnly) { + ParameterDefinition definition = + new ParameterDefinition(identity, description, rawType, rawUnit, convertedType, convertedUnit); + if (!definitions.add(definition)) { + IllegalArgumentException exc = new IllegalArgumentException( + "cannot add the ParameterDefinition object to the list"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + int parameterID = definitions.size()-1; + logger.info("parameter " + parameterID + " added: " + definition); + if (!defaultConfigs.add(config)) { + IllegalArgumentException exc = new IllegalArgumentException( + "cannot add the default configuration to the list"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + if (!conversionFunctions.add(conversionFunction)) { + IllegalArgumentException exc = new IllegalArgumentException( + "cannot add the conversion function to the list"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + if (!readOnlyProperties.add(readOnly)) { + IllegalArgumentException exc = new IllegalArgumentException( + "cannot add the read-only property to the list"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + return parameterID; + } + + /** + * List of time stamped Parameter values used in the dataset. + * Values are ordered by timestamp and samplingTime. + */ + private ArrayList> parameterValues; + + /** + * Adds a Parameter value to the list of values used in the dataset. + * Values for a Parameter must be added in a growing timestamp/samplingTime order. + * This method is expected to be called by the specific test backend, at initialization time. + * + * The timestamp of the Parameter value is used be the {@link getValue} method to know if the value + * has been received, as compared to the current time provided by the backend timer. + * + * @param parameterID identifier of the Parameter + * @param timestamp timestamp of the Parameter value + * @param samplingTime sampling time of the Parameter value + * @param rawValue raw value of the Parameter + */ + protected void addParameterValue( + int parameterID, + long timestamp, + long samplingTime, + Attribute rawValue) { + logger.info("add parameter value for " + parameterID); + if (parameterID >= definitions.size()) { + IllegalArgumentException exc = new IllegalArgumentException("unknown ParameterDefinition id"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + ParameterRawValue value = new ParameterRawValue(timestamp, samplingTime, rawValue); + if (parameterValues == null) { + parameterValues = new ArrayList<>(definitions.size()); + for (int i = 0; i < definitions.size(); i++) + parameterValues.add(new Vector<>()); + } + List vlist = parameterValues.get(parameterID); + ParameterRawValue lastValue = null; + if (!vlist.isEmpty()) + lastValue = vlist.get(vlist.size()-1); + if (lastValue != null && + (timestamp < lastValue.timestamp || + timestamp == lastValue.timestamp && samplingTime <= lastValue.samplingTime)) { + IllegalArgumentException exc = new IllegalArgumentException("misordered Parameter value"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + vlist.add(value); + logger.info("parameter value added: " + value); + } + + @Override + public ParameterRawValue getValue(int parameterID) { + logger.info("getValue " + parameterID); + if (timer == null) { + IllegalStateException exc = new IllegalStateException("backend timer has not been set"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + + if (parameterID >= definitions.size()) { + logger.severe("unknown ParameterDefinition id"); + return null; + } + + long now = timer.currentTimeMillis(); + logger.info("now=" + now); + List vlist = parameterValues.get(parameterID); + ParameterRawValue currentValue = null; + if (vlist.isEmpty()) { + logger.info("no value for " + parameterID); + } else { + boolean found = false; + for (int i=0; !found && i now) { + found = true; + } else { + currentValue = svalue; + } + } + } + + logger.info("backend getValue(" + parameterID + ") return " + currentValue); + return currentValue; + } + + @Override + public boolean isReadOnly(int parameterID) { + if (parameterID >= defaultConfigs.size()) { + IllegalArgumentException exc = new IllegalArgumentException("unknown ParameterDefinition id"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + return readOnlyProperties.get(parameterID); + } + + @Override + public ConversionFunction getConversionFunction(int parameterID) { + if (parameterID >= defaultConfigs.size()) { + IllegalArgumentException exc = new IllegalArgumentException("unknown ParameterDefinition id"); + logger.log(Level.SEVERE, null, exc); + throw exc; + } + return conversionFunctions.get(parameterID); + } + + /** + * Simple conversion function with no converted value and simple validity state. + * + * @param parameterID index of the parameter definition + * @param rawValue raw value of the parameter + * @return the complete parameter value as a {@link ParameterValueData} object, with updated + * validityState and convertedValue fields. + */ + protected static ParameterValueData noConversionFunction( + int parameterID, + ParameterRawValue rawValue) { + if (rawValue == null || rawValue.rawValue == null) + return new ParameterValueData(ValidityState.INVALID_RAW, null, null); + return new ParameterValueData(ValidityState.VALID, rawValue.rawValue, null); + } + } diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ActionBackend.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ActionBackend.java index 9c0c669a3..1a7f75a8a 100644 --- a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ActionBackend.java +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ActionBackend.java @@ -4,6 +4,9 @@ * Darmstadt * Germany * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- * System : CCSDS MO services * ---------------------------------------------------------------------------- * Licensed under the European Space Agency Public License, Version 2.0 @@ -20,9 +23,59 @@ */ package org.ccsds.moims.mo.mc.backends; +import org.ccsds.moims.mo.mc.structures.ActionDefinition; +import org.ccsds.moims.mo.mc.structures.ActionDefinitionList; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; + /** * The Backend interface to the Action service. */ public interface ActionBackend { + /** + * Retrieves the Definition objects for all known Actions of the provider. + * This list is static. + * + * @return the list of ActionDefinition objects known by the provider + */ + public ActionDefinitionList getAllActionDefinitions(); + + /** + * Listener interface used in calling {@link execute}. + */ + public interface ExecuteListener { + /** + * Signals the success in executing the next step. + */ + public void progressReport(); + } + + /** + * Checks that an Action execution request is ready for execution. + * This function is called before {@link execute} to allow the provider to perform + * some acceptance tests before actually executing the Action. + * + * @param executionRequest request planned for execution + * @param definition definition of the request Action + * @return null if the request is ready for execution, or an error message otherwise. + */ + public String check( + ActionExecutionRequest executionRequest, + ActionDefinition definition); + + /** + * Actually executes an Action. + * Successful progress steps are reported via the ExecuteListener interface. + * The function returns when the execution completes, and reports the success status of the execution. + * + * @param executionRequest request to execute + * @param definition definition of the request Action + * @param listener listener to report execution progress to + * @return the success status of the execution. + */ + public boolean execute( + ActionExecutionRequest executionRequest, + ActionDefinition definition, + ExecuteListener listener); + } diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/AggregationBackend.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/AggregationBackend.java new file mode 100755 index 000000000..a83636faf --- /dev/null +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/AggregationBackend.java @@ -0,0 +1,126 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO services + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.moims.mo.mc.backends; + +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mc.structures.AggregationDefinitionList; + +/** + * The Backend interface to the Aggregation service. + * + * In the testbed, we consider that the Aggregation provider gets the values of the aggregations parameters + * from a Parameter provider. The Aggregation backend interface reflects this choice. + * The method {@link getParameterConnectionDetails} allows the Aggregation provider to retrieve the + * connection details to the Parameter provider. + * + * The Aggregation backend requires a {@link BackendTimer} to answer to time related calls. The timer is provided + * in the constructor of the concrete classes implementing the AggregationBackend, and can be + * retrieved by the {@link getTimer} method. This timer should be the same as the Parameter backend's. + * + * Unlike other M&C service, the Aggregation service allows to define new object Definitions. This does not + * show in the backend interface. Dynamically defined aggregations will be handled completely by the Aggregation + * provider. There is however a specific method in the backend to retrieve the default configuration of those + * dynamically defined aggregations. + */ +public interface AggregationBackend { + + /** + * Gets the timer of this backend. + * The timer must be set in the backend constructor. + * + * @return timer + */ + public BackendTimer getTimer(); + + /** + * Retrieves the Definition objects for all known Aggregations of the provider. + * Aggregations are then identified by their index in this list. + * + * @return the list of AggregationDefinition objects known by the provider + */ + public AggregationDefinitionList getAllAggregationDefinitions(); + + /** + * The DefaultReportConfiguration class is used to provide the default report configuration of an + * Aggregation, in the {@link getDefaultReportConfig} method. + */ + public class DefaultReportConfiguration { + public boolean generationEnabled; + public long reportInterval; // ms + public DefaultReportConfiguration( + boolean generationEnabled, + long reportInterval) { + this.generationEnabled = generationEnabled; + this.reportInterval = reportInterval; + } + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("DefaultReportConfiguration{"); + result.append("generationEnabled=").append(generationEnabled); + result.append(",reportInterval=").append(reportInterval); + result.append("}"); + return result.toString(); + } + } + + /** + * retrieves the default reporting configuration for the requested Aggregation. + * + * @param aggregationID index of the requested aggregation reporting configuration + * @return the default reporting configuration of the aggregation + */ + public DefaultReportConfiguration getDefaultReportConfig(int aggregationID); + + /** + * retrieves the default reporting configuration for supplementary Aggregations. + * + * @return the default reporting configuration for supplementary aggregations + */ + public DefaultReportConfiguration getDefaultReportConfig(); + + /** + * retrieves the list of the deployment specific allowed values. + * + * @return the list of allowed category values, may be null + */ + public IdentifierList getCategories(); + + /** + * Retrieves the details of the Parameter provider used to collect the Parameter values. + * + * @return + */ + public SingleConnectionDetails getParameterConnectionDetails(); + + /** + * Verifies that the provided identifier is valid according to the provider's specific rules. + * @param domain domain part of the aggregation identifier + * @param key key part of the aggregation identifier + * @return true if the identifier is valid + */ + public boolean isValidId(IdentifierList domain, Identifier key); + +} diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/AlertBackend.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/AlertBackend.java index 00aa7c864..3c69f2b45 100644 --- a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/AlertBackend.java +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/AlertBackend.java @@ -4,6 +4,9 @@ * Darmstadt * Germany * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- * System : CCSDS MO services * ---------------------------------------------------------------------------- * Licensed under the European Space Agency Public License, Version 2.0 @@ -20,9 +23,55 @@ */ package org.ccsds.moims.mo.mc.backends; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mc.structures.AlertDefinitionList; + /** * The Backend interface to the Alert service. + * + * The original Alert service was associating a condition to the Alert, defining in details the computation + * to perform to known when the Alert was to be reported. This alert condition part is no longer normative. + * We have nevertheless decided to keep this idea of a condition in the backend interface, even if there is + * no actual definition or structure related to the condition. + * + * The backend provides a dynamic API to signal changes in the computed value of an Alert condition. + * It may be a change of status, i.e. the condition holds false while it was holding true before, + * or a change in the values of the Alert arguments. */ public interface AlertBackend { + /** + * Retrieves the Definition objects for all known Alerts of the provider. + * Alerts are then identified by their index in this list. + * This list is static. + * + * @return the list of AlertDefinition objects known by the provider + */ + public AlertDefinitionList getAllAlertDefinitions(); + + /** + * Listener interface used in calling {@link register}. + */ + public interface AlertListener { + /** + * Signals a change of value for the condition of an Alert. + */ + public void notifyAlertCondition(int alertID, boolean status, NullableAttributeList arguments); + } + + /** + * Registers a listener for receiving changes of condition value for all Alerts. + * + * @param listener listener to notify + */ + public void register(AlertListener listener); + + /** + * Unregisters a listener for the condition values changes. + * Returns silently if the provided listener was not previously registered. + * + * @param listener listener to unregister for notifications + */ + public void deregister(AlertListener listener); + } diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/BackendTimer.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/BackendTimer.java new file mode 100755 index 000000000..a99eac562 --- /dev/null +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/BackendTimer.java @@ -0,0 +1,75 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : ESA CCSDS MO Services + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.moims.mo.mc.backends; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionException; + +/** + * Provides a Timer interface to use by the provider to allow simulating a virtual time during tests. + */ +public interface BackendTimer { + + /** + * Initializes the timer. + * + * @param origin time origin (ms since Epoch) in the test implementation, + * may be ignored in a standard implementation. + */ + public void init(long origin); + + /** + * Stops the timer. + * Frees all waiting threads. + */ + public void stop(); + + /** + * Gets the current virtual time of the timer in milliseconds. + * This results in a call to {@link System.currentTimeMillis} in a standard implementation. + * + * @return the current time + */ + public long currentTimeMillis(); + + /** + * Causes the currently executing thread to sleep for the specified number of milliseconds of virtual time. + * This results in a call to {@link Thread.sleep} in a standard implementation. + * + * @param millis time to wait in milliseconds + * @throws InterruptedException + */ + public void sleep(long millis) + throws InterruptedException; + + /** + * Submits a one-shot task that will be planified for execution by the provided Executor + * after the specified number of milliseconds of virtual time. + * This results in a call to {@link ScheduledExecutorService.schedule} in a standard implementation. + * + * @param command task to execute + * @param executor executor to use for executing the task + * @param delay delay in milliseconds before executing the task + * @throws RejectedExecutionException + * @throws NullPointerException + */ + public void schedule(Runnable command, ExecutorService executor, long delay) + throws RejectedExecutionException, NullPointerException; + +} diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ConversionFunction.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ConversionFunction.java new file mode 100755 index 000000000..dee35ef61 --- /dev/null +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ConversionFunction.java @@ -0,0 +1,46 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO services + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.moims.mo.mc.backends; + +import org.ccsds.moims.mo.mc.backends.ParameterBackend.ParameterRawValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; + +/** + * This single method interface describes the conversion function of a Parameter. + * It is no longer explicitly part of the latest specification of the service, however it is required + * to compute the converted value of a parameter from its raw value. It is notably used when the raw value + * is provided by the service consumer. + * + * We also have the need to compute the validity state of a parameter from its raw value. We decided to reuse + * the same operation for both usages, meaning that the function is called even for parameters which do not + * use converted values. + */ +public interface ConversionFunction { + + /** + * Computes the validity state and possibly the converted value of a parameter. + * + * @param parameterID index of the parameter definition + * @param rawValue raw value of the parameter + * @return the complete parameter value as a {@link ParameterValueData} object, with updated + * validityState and convertedValue fields. + */ + public ParameterValueData getConvertedValue(int parameterID, ParameterRawValue rawValue); + +} diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/PacketBackend.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/PacketBackend.java index a6feb6839..2379bcdd2 100644 --- a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/PacketBackend.java +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/PacketBackend.java @@ -4,6 +4,9 @@ * Darmstadt * Germany * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- * System : CCSDS MO services * ---------------------------------------------------------------------------- * Licensed under the European Space Agency Public License, Version 2.0 @@ -20,9 +23,68 @@ */ package org.ccsds.moims.mo.mc.backends; +import org.ccsds.moims.mo.mal.structures.AttributeTypeList; +import org.ccsds.moims.mo.mal.structures.Blob; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mc.backends.AlertBackend.AlertListener; + /** * The Backend interface to the Packet service. + * + * The Packet service specifically allows (and recommends) to define custom subscription keys to its main + * PubSub operation. The Backend interface includes methods to retrieve the details of these keys. + * + * */ public interface PacketBackend { + /** + * Retrieves the names of the custom subscription keys of the deliverPacket operation. + * + * @return the list of key names + */ + public IdentifierList getCustomSubscriptionKeyNames(); + /** + * Retrieves the types of the custom subscription keys of the deliverPacket operation. + * + * @return the list of key types + */ + public AttributeTypeList getCustomSubscriptionKeyTypes(); + + /** + * Listener interface used in calling {@link register}. + */ + public interface PacketListener { + /** + * Notifies a new Packet. + * + * @param domain domain of the packet to publish + * @param keyValues values of all subscription keys, including the standard apid and the custom ones + * @param timestamp timestamp of the packet + * @param spacePacket body of the packet + */ + public void notifyPacket( + IdentifierList domain, + NullableAttributeList keyValues, + Time timestamp, + Blob spacePacket); + } + + /** + * Registers a listener for receiving all new Packets. + * + * @param listener listener to notify + */ + public void register(PacketListener listener); + + /** + * Unregisters a listener for the new Packets. + * Returns silently if the provided listener was not previously registered. + * + * @param listener listener to unregister for notifications + */ + public void deregister(PacketListener listener); + } diff --git a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ParameterBackend.java b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ParameterBackend.java index 23849812b..c4f222574 100644 --- a/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ParameterBackend.java +++ b/apis/api-area004-v002-mc/src/main/java/org/ccsds/moims/mo/mc/backends/ParameterBackend.java @@ -4,6 +4,9 @@ * Darmstadt * Germany * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- * System : CCSDS MO services * ---------------------------------------------------------------------------- * Licensed under the European Space Agency Public License, Version 2.0 @@ -20,9 +23,126 @@ */ package org.ccsds.moims.mo.mc.backends; +import java.io.IOException; + +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mc.structures.ParameterDefinitionList; + /** * The Backend interface to the Parameter service. + * + * The Parameter backend requires a {@link BackendTimer} to answer to time related calls. The timer is provided + * in the constructor of the concrete classes implementing the ParameterBackend, and can be + * retrieved by the {@link getTimer} method. + * + * Note that the setValue operation of the service is not included in the backend interface. This operation + * must be completely handled by the provider implementation. */ public interface ParameterBackend { -} + /** + * Gets the timer of this backend. + * The timer must be set in the backend constructor. + * + * @return timer + */ + public BackendTimer getTimer(); + + /** + * Retrieves the Definition objects for all known Parameters of the provider. + * Parameters are then identified by their index in this list. + * This list is static. + * + * @return the list of ParameterDefinition objects known by the provider + */ + public ParameterDefinitionList getAllParameterDefinitions(); + + /** + * The DefaultReportConfiguration class is used to provide the default report configuration of a + * Parameter, in the {@link getDefaultReportConfig} method. + */ + public class DefaultReportConfiguration { + public boolean generationEnabled; + public long reportInterval; // ms + public long minimalReportInterval; // ms + public DefaultReportConfiguration( + boolean generationEnabled, + long reportInterval, + long minimalReportInterval) { + this.generationEnabled = generationEnabled; + this.reportInterval = reportInterval; + this.minimalReportInterval = minimalReportInterval; + } + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("DefaultReportConfiguration{"); + result.append("generationEnabled=").append(generationEnabled); + result.append(",reportInterval=").append(reportInterval); + result.append(",minimalReportInterval=").append(minimalReportInterval); + result.append("}"); + return result.toString(); + } + } + + /** + * retrieves the default reporting configuration for the requested Parameter. + * + * @param parameterID index of the requested parameter reporting configuration + * @return the default reporting configuration of the parameter + */ + public DefaultReportConfiguration getDefaultReportConfig(int parameterID); + + /** + * The ParameterRawValue class is used to provide the latest known raw value of a Parameter, + * in the {@link getValue} method. + */ + public class ParameterRawValue { + public long timestamp; + public long samplingTime; + public Attribute rawValue; + public ParameterRawValue( + long timestamp, + long samplingTime, + Attribute rawValue) { + this.timestamp = timestamp; + this.samplingTime = samplingTime; + this.rawValue = rawValue; + } + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("ParameterRawValue{"); + result.append("timestamp=").append(timestamp); + result.append(",samplingTime=").append(samplingTime); + result.append(",rawValue=").append(rawValue); + result.append("}"); + return result.toString(); + } + } + + /** + * Retrieves the latest known raw value of the parameter at the current time, + * together with its timestamp and sampling time. The current time is retrieved from the backend timer. + * + * @param parameterID index of the requested parameter value + * @return the latest known raw value of the parameter, or null if no value is known for + * the parameter at the current time + */ + public ParameterRawValue getValue(int parameterID); + + /** + * Gets the read-only property of a Parameter. + * + * @param parameterID index of the requested parameter + * @return true if the Parameter is read-only, false otherwise + */ + public boolean isReadOnly(int parameterID); + + /** + * Retrieves the conversion function associated to the parameter. + * + * @param parameterID index of the requested parameter conversion function + * @return the conversion function associated to the parameter + */ + public ConversionFunction getConversionFunction(int parameterID); + +} \ No newline at end of file diff --git a/services-impl/services-area004-v002-mc/src/main/java/esa/mo/services/mc/provider/AggregationProviderServiceImpl.java b/services-impl/services-area004-v002-mc/src/main/java/esa/mo/services/mc/provider/AggregationProviderServiceImpl.java index 282d94967..e31a937f2 100644 --- a/services-impl/services-area004-v002-mc/src/main/java/esa/mo/services/mc/provider/AggregationProviderServiceImpl.java +++ b/services-impl/services-area004-v002-mc/src/main/java/esa/mo/services/mc/provider/AggregationProviderServiceImpl.java @@ -31,7 +31,7 @@ import org.ccsds.moims.mo.mal.structures.IdentifierList; import org.ccsds.moims.mo.mc.aggregation.AggregationHelper; import org.ccsds.moims.mo.mc.aggregation.provider.AggregationInheritanceSkeleton; -import org.ccsds.moims.mo.mc.backends.ParameterBackend; +import org.ccsds.moims.mo.mc.backends.AggregationBackend; import org.ccsds.moims.mo.mc.structures.AggregationDefinitionList; import org.ccsds.moims.mo.mc.structures.AggregationValueList; import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; @@ -44,7 +44,7 @@ public class AggregationProviderServiceImpl extends AggregationInheritanceSkelet private static final Logger LOGGER = Logger.getLogger(AggregationProviderServiceImpl.class.getName()); private final ConnectionProvider connection = new ConnectionProvider(); - private ParameterBackend backend; + private AggregationBackend backend; private MALProvider service; private boolean running = false; @@ -54,7 +54,7 @@ public class AggregationProviderServiceImpl extends AggregationInheritanceSkelet * @param backend The backend of this service. * @throws MALException On initialisation error. */ - public synchronized void init(ParameterBackend backend) throws MALException { + public synchronized void init(AggregationBackend backend) throws MALException { if (backend == null) { throw new IllegalArgumentException("The backend cannot be null!"); } diff --git a/services-impl/services-area004-v002-mc/src/main/java/esa/mo/services/mc/util/ESAMCServicesFactory.java b/services-impl/services-area004-v002-mc/src/main/java/esa/mo/services/mc/util/ESAMCServicesFactory.java index e2f4e0581..61c43cf05 100644 --- a/services-impl/services-area004-v002-mc/src/main/java/esa/mo/services/mc/util/ESAMCServicesFactory.java +++ b/services-impl/services-area004-v002-mc/src/main/java/esa/mo/services/mc/util/ESAMCServicesFactory.java @@ -38,6 +38,7 @@ import org.ccsds.moims.mo.mc.alert.consumer.AlertStub; import org.ccsds.moims.mo.mc.alert.provider.AlertInheritanceSkeleton; import org.ccsds.moims.mo.mc.backends.ActionBackend; +import org.ccsds.moims.mo.mc.backends.AggregationBackend; import org.ccsds.moims.mo.mc.backends.AlertBackend; import org.ccsds.moims.mo.mc.backends.PacketBackend; import org.ccsds.moims.mo.mc.backends.ParameterBackend; @@ -66,8 +67,8 @@ public ActionInheritanceSkeleton createProviderAction(ActionBackend backend) thr } @Override - public AggregationInheritanceSkeleton createProviderAggregation(ParameterBackend backend) throws MALException { - if (parameterService == null) { + public AggregationInheritanceSkeleton createProviderAggregation(AggregationBackend backend) throws MALException { + if (aggregationService == null) { throw new MALException("The backend needs to be instantiated before!"); } diff --git a/testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/LocalMALInstanceMAL.properties b/testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/LocalMALInstanceMAL.properties new file mode 100755 index 000000000..3d2fc13f4 --- /dev/null +++ b/testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/LocalMALInstanceMAL.properties @@ -0,0 +1,22 @@ +# ---------------------------------------------------------------------------- +# Copyright (C) 2013 European Space Agency +# European Space Operations Centre +# Darmstadt +# Germany +# ---------------------------------------------------------------------------- +# System : CCSDS MO MAL Test bed +# ---------------------------------------------------------------------------- +# Licensed under the European Space Agency Public License, Version 2.0 +# You may not use this file except in compliance with the License. +# +# Except as expressly set forth in this License, the Software is provided to +# You on an "as is" basis and without warranties of any kind, including without +# limitation merchantability, fitness for a particular purpose, absence of +# defects or errors, accuracy or non-infringement of intellectual property rights. +# +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +#org.ccsds.moims.mo.mal.transport.gen.debug=false +org.ccsds.moims.mo.mal.transport.gen.wrap=false \ No newline at end of file diff --git a/testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/TestServiceProviderMAL.properties b/testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/TestServiceProviderMAL.properties new file mode 100755 index 000000000..3d2fc13f4 --- /dev/null +++ b/testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/TestServiceProviderMAL.properties @@ -0,0 +1,22 @@ +# ---------------------------------------------------------------------------- +# Copyright (C) 2013 European Space Agency +# European Space Operations Centre +# Darmstadt +# Germany +# ---------------------------------------------------------------------------- +# System : CCSDS MO MAL Test bed +# ---------------------------------------------------------------------------- +# Licensed under the European Space Agency Public License, Version 2.0 +# You may not use this file except in compliance with the License. +# +# Except as expressly set forth in this License, the Software is provided to +# You on an "as is" basis and without warranties of any kind, including without +# limitation merchantability, fitness for a particular purpose, absence of +# defects or errors, accuracy or non-infringement of intellectual property rights. +# +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +#org.ccsds.moims.mo.mal.transport.gen.debug=false +org.ccsds.moims.mo.mal.transport.gen.wrap=false \ No newline at end of file diff --git a/testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/a3debug.cfg b/testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/a3debug.cfg new file mode 100755 index 000000000..4bae83ef3 --- /dev/null +++ b/testbeds/testbed-mal/src/main/resources/deployment/cnes-rmi/a3debug.cfg @@ -0,0 +1,66 @@ +# +# Copyright or © or Copr. CNES +# +# This software is a computer program whose purpose is to provide a +# framework for the CCSDS Mission Operations services. +# +# This software is governed by the CeCILL-C license under French law and +# abiding by the rules of distribution of free software. You can use, +# modify and/ or redistribute the software under the terms of the CeCILL-C +# license as circulated by CEA, CNRS and INRIA at the following URL +# "http://www.cecill.info". +# +# As a counterpart to the access to the source code and rights to copy, +# modify and redistribute granted by the license, users are provided only +# with a limited warranty and the software's author, the holder of the +# economic rights, and the successive licensors have only limited +# liability. +# +# In this respect, the user's attention is drawn to the risks associated +# with loading, using, modifying and/or developing or reproducing the +# software by the user in light of its specific status of free software, +# that may mean that it is complicated to manipulate, and that also +# therefore means that it is reserved for developers and experienced +# professionals having in-depth computer knowledge. Users are therefore +# encouraged to load and test the software's suitability as regards their +# requirements in conditions enabling the security of their systems and/or +# data to be ensured and, more generally, to use and operate it in the +# same conditions as regards security. +# +# The fact that you are presently reading this means that you have had +# knowledge of the CeCILL-C license and that you accept its terms. +# + +log.config.classname org.objectweb.util.monolog.wrapper.log4j.MonologLoggerFactory + +# ============================== +# tty : console handler +handler.tty.type Console +handler.tty.output System.err +handler.tty.pattern %l %d, %m%n + +# ============================== +# logf : rolling file handler +handler.logf.type File +handler.logf.output server.log +handler.logf.pattern %l %d, %m%n + +# ============================== +# logger definitions +logger.root.handler.0 logf + +logger.root.level WARN + +# ============================== +# ScalAgent middleware +# logger.fr.dyade.aaa.level DEBUG + +# logger.fr.dyade.aaa.agent.Agent WARN +# logger.fr.dyade.aaa.agent.AgentServer DEBUG +# logger.fr.dyade.aaa.agent.Engine WARN +# logger.fr.dyade.aaa.agent.Network WARN +# logger.fr.dyade.aaa.agent.ConfigController.level DEBUG +# logger.fr.dyade.aaa.agent.Transaction INFO + +logger.fr.cnes.level DEBUG +logger.org.ccsds.level DEBUG \ No newline at end of file diff --git a/testbeds/testbed-mc/logging.properties b/testbeds/testbed-mc/logging.properties new file mode 100755 index 000000000..894f56ca1 --- /dev/null +++ b/testbeds/testbed-mc/logging.properties @@ -0,0 +1,2 @@ +.level= ALL +java.util.logging.ConsoleHandler.level= ALL \ No newline at end of file diff --git a/testbeds/testbed-mc/pom.xml b/testbeds/testbed-mc/pom.xml index f9839e602..4ec6d2d00 100644 --- a/testbeds/testbed-mc/pom.xml +++ b/testbeds/testbed-mc/pom.xml @@ -133,12 +133,12 @@ CNES - CNES-TBD - CNES-TBD + fr.cnes.ccsds.mo.mc.util.CNESMCServicesFactory + fr.cnes.ccsds.mo.mc.util.CNESMCServicesFactory - CNES-TBD + fr.cnes.ccsds.mo services-area004-v002-mc 1.0 diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/Constant.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/Constant.java new file mode 100755 index 000000000..df373a23c --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/Constant.java @@ -0,0 +1,117 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.ULong; +import org.ccsds.moims.mo.mal.structures.Union; + +/** + * Defines constants used in both consumers and providers of the M&C testbed. + * + * @author serge.lacourte + * + */ +public class Constant { + + // used in all test services + + // domain values + public static final Identifier ID_FR = new Identifier("fr"); + public static final Identifier ID_CNES = new Identifier("cnes"); + public static final Identifier ID_MISSION = new Identifier("mission"); + public static final Identifier ID_SAT1 = new Identifier("sat1"); + public static final IdentifierList DOMAIN_SAT1 = + new IdentifierList(new ArrayList<> (Arrays.asList(ID_FR, ID_CNES, ID_MISSION, ID_SAT1))); + public static final Identifier ID_SAT2 = new Identifier("sat2"); + public static final IdentifierList DOMAIN_SAT2 = + new IdentifierList(new ArrayList<> (Arrays.asList(ID_FR, ID_CNES, ID_MISSION, ID_SAT2))); + public static final Identifier ID_WILDCARD = new Identifier("*"); + public static final IdentifierList DOMAIN_WILDCARD = + new IdentifierList(new ArrayList<> (Arrays.asList(ID_FR, ID_CNES, ID_MISSION, ID_WILDCARD))); + public static final Identifier ID_UNKNOWN = new Identifier("unknown"); + public static final IdentifierList DOMAIN_UNKNOWN = + new IdentifierList(new ArrayList<> (Arrays.asList(ID_FR, ID_CNES, ID_MISSION, ID_UNKNOWN))); + + + // used in Action test service + + // ActionDefinition keys + public static final Identifier ID_CHGTABSVAL = new Identifier("SAT_TC_CHGTABSVAL"); + public static final Identifier ID_DEFATTITUDE = new Identifier("MIS_TC_DEFATTITUDE"); + + // ArgumentDefinition keys + public static final Identifier ID_TIMEABSVAL = new Identifier("GENE_AR_TIMEABSVAL"); + public static final Identifier ID_STARTTIME = new Identifier("GENE_AR_STARTTIME"); + public static final Identifier ID_DURATION = new Identifier("GENE_AR_DURATION"); + public static final Identifier ID_MANEUVTYPE = new Identifier("GENE_AR_MANEUVTYPE"); + public static final Identifier ID_POLYNOMDEG = new Identifier("GENE_AR_POLYNOMDEG"); + public static final Identifier ID_POLVALUE = new Identifier("GENE_AR_POLVALUE"); + + // specific values of the GENE_AR_MANEUVTYPE argument + public static final String STR_OK = "ok"; + public static final String STR_STEPS = "steps"; + public static final String STR_SKIP = "skip"; + public static final String STR_WAIT = "wait"; + public static final String STR_FAIL2 = "fail-2"; + + // specific value of the extraInfo error field + public static final String STR_SKIPPED = "skipped"; + + // used in Parameter test service + + // ParameterDefinition keys + public static final Identifier ID_MTQ1VOLTAGE = new Identifier("ATT_BC_MTQ1VOLTAGE"); + public static final Identifier ID_MTQ1ENABLED = new Identifier("ATT_BC_MTQ1ENABLED"); + + // converted values + public static final String STR_DISABLED = "DISABLED"; + public static final String STR_ENABLED = "ENABLED"; + public static final String STR_UNKNOWN = "UNKNOWN"; + public static final Attribute AT_STRING_DISABLED = new Union(Constant.STR_DISABLED); + public static final Attribute AT_STRING_ENABLED = new Union(Constant.STR_ENABLED); + public static final Attribute AT_STRING_UNKNOWN = new Union(Constant.STR_UNKNOWN); + + // used in Alert test service + + // AlertDefinition keys + public static final Identifier ID_MTQ1VOLTAGE_HIGH = new Identifier("MTQ1VOLTAGE_HIGH"); + public static final Identifier ID_MTQ1VOLTAGE_LOW = new Identifier("MTQ1VOLTAGE_LOW"); + + // ArgumentDefinition keys + public static final Identifier ID_MTQ1VOLTAGE_HIGH_VAL = new Identifier("MTQ1VOLTAGE_HIGH_VAL"); + + // used in Aggregation test service + + // AggregationDefinition keys + public static final Identifier ID_BC_MTQ1 = new Identifier("AGG_BC_MTQ1"); + public static final Identifier ID_BC_MTQ1_REV = new Identifier("AGG_BC_MTQ1_REV"); + + // used in Packet service + + public static final Identifier ID_APID = new Identifier("apid"); + public static final Identifier ID_DESTID = new Identifier("destID"); + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/SetUpProvidersAndConsumers.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/SetUpProvidersAndConsumers.java index cd080a06c..4b7068afe 100644 --- a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/SetUpProvidersAndConsumers.java +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/SetUpProvidersAndConsumers.java @@ -4,7 +4,7 @@ * Darmstadt * Germany * ---------------------------------------------------------------------------- - * System : CCSDS MO Testbed + * System : CCSDS MO Testbed - M&C * ---------------------------------------------------------------------------- * Licensed under the European Space Agency Public License, Version 2.0 * You may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ public class SetUpProvidersAndConsumers { private static ParameterInheritanceSkeleton parameterProviderService = null; private static ParameterStub parameterConsumerStub = null; - public void setUp(ActionBackend actionBackend, AlertBackend alertBackend, + public void setUp(ActionBackend actionBackend, AggregationBackend aggregationBackend, AlertBackend alertBackend, PacketBackend packetBackend, ParameterBackend parameterBackend, boolean startAction, boolean startAggregation, boolean startAlert, boolean startPacket, boolean startParameter) throws IOException { @@ -90,13 +90,18 @@ public void setUp(ActionBackend actionBackend, AlertBackend alertBackend, // Provider Factory: Class factoryClassProvider = Class.forName(factoryClassForProvider); + System.out.println("factoryClassProvider=" + factoryClassProvider); MCServicesFactory factoryProvider = (MCServicesFactory) factoryClassProvider.newInstance(); + System.out.println("factoryProvider=" + factoryProvider); // Consumer Factory: Class factoryClassConsumer = Class.forName(factoryClassForConsumer); + System.out.println("factoryClassConsumer=" + factoryClassConsumer); MCServicesFactory factoryConsumer = (MCServicesFactory) factoryClassConsumer.newInstance(); + System.out.println("factoryConsumer=" + factoryConsumer); if (startAction) { actionProviderService = factoryProvider.createProviderAction(actionBackend); + System.out.println("actionProviderService=" + actionProviderService); if (actionProviderService == null) { throw new MALException("The Action service provider was not created!"); @@ -104,10 +109,11 @@ public void setUp(ActionBackend actionBackend, AlertBackend alertBackend, SingleConnectionDetails details = actionProviderService.getConnection().getConnectionDetails(); actionConsumerStub = factoryConsumer.createConsumerStubAction(details); + System.out.println("actionConsumerStub=" + actionConsumerStub); } if (startAggregation) { - aggregationProviderService = factoryProvider.createProviderAggregation(parameterBackend); + aggregationProviderService = factoryProvider.createProviderAggregation(aggregationBackend); if (aggregationProviderService == null) { throw new MALException("The Aggregation service provider was not created!"); @@ -160,6 +166,117 @@ public void setUp(ActionBackend actionBackend, AlertBackend alertBackend, } } + /** + * Updates the setup. + * This function is created to solved the initialization issue of the Aggregation provider. + * The Aggregation test backends rely on the prior initialization of the Parameter service. + * This function is used to initialize the Aggregation provider, after the Parameter provider + * has been initialized in the setUp call. + */ + public void updateSetUp(ActionBackend actionBackend, AggregationBackend aggregationBackend, + AlertBackend alertBackend, PacketBackend packetBackend, ParameterBackend parameterBackend, + boolean startAction, boolean startAggregation, boolean startAlert, + boolean startPacket, boolean startParameter) throws IOException { + HelperMisc.loadPropertiesFile(); + + try { + // Dynamic load here: It can be either for ESA's or CNES's implementation + // And also the consumer and provider need to be selectable! + // This can be achieved with the Factory pattern + + String factoryClassForProvider = System.getProperty("testbed.provider"); + String factoryClassForConsumer = System.getProperty("testbed.consumer"); + System.out.println(" >> factoryClassForProvider: " + factoryClassForProvider); + System.out.println(" >> factoryClassForConsumer: " + factoryClassForConsumer); + + if ("null".equals(factoryClassForProvider) || "".equals(factoryClassForProvider)) { + throw new IOException("The classname is empty or null for the provider side! " + + "Please select the correct Maven profile before running the test!"); + } + + if ("null".equals(factoryClassForConsumer) || "".equals(factoryClassForConsumer)) { + throw new IOException("The classname is empty or null for the consumer side! " + + "Please select the correct Maven profile before running the test!"); + } + + // Provider Factory: + Class factoryClassProvider = Class.forName(factoryClassForProvider); + System.out.println("factoryClassProvider=" + factoryClassProvider); + MCServicesFactory factoryProvider = (MCServicesFactory) factoryClassProvider.newInstance(); + System.out.println("factoryProvider=" + factoryProvider); + // Consumer Factory: + Class factoryClassConsumer = Class.forName(factoryClassForConsumer); + System.out.println("factoryClassConsumer=" + factoryClassConsumer); + MCServicesFactory factoryConsumer = (MCServicesFactory) factoryClassConsumer.newInstance(); + System.out.println("factoryConsumer=" + factoryConsumer); + + if (startAction && actionProviderService == null) { + actionProviderService = factoryProvider.createProviderAction(actionBackend); + System.out.println("actionProviderService=" + actionProviderService); + + if (actionProviderService == null) { + throw new MALException("The Action service provider was not created!"); + } + + SingleConnectionDetails details = actionProviderService.getConnection().getConnectionDetails(); + actionConsumerStub = factoryConsumer.createConsumerStubAction(details); + System.out.println("actionConsumerStub=" + actionConsumerStub); + } + + if (startAggregation && aggregationProviderService == null) { + aggregationProviderService = factoryProvider.createProviderAggregation(aggregationBackend); + + if (aggregationProviderService == null) { + throw new MALException("The Aggregation service provider was not created!"); + } + + SingleConnectionDetails details = aggregationProviderService.getConnection().getConnectionDetails(); + aggregationConsumerStub = factoryConsumer.createConsumerStubAggregation(details); + } + + if (startAlert && alertProviderService == null) { + alertProviderService = factoryProvider.createProviderAlert(alertBackend); + + if (alertProviderService == null) { + throw new MALException("The Alert service provider was not created!"); + } + + SingleConnectionDetails details = alertProviderService.getConnection().getConnectionDetails(); + alertConsumerStub = factoryConsumer.createConsumerStubAlert(details); + } + + if (startPacket && packetProviderService == null) { + packetProviderService = factoryProvider.createProviderPacket(packetBackend); + + if (packetProviderService == null) { + throw new MALException("The Packet service provider was not created!"); + } + + SingleConnectionDetails details = packetProviderService.getConnection().getConnectionDetails(); + packetConsumerStub = factoryConsumer.createConsumerStubPacket(details); + } + + if (startParameter && parameterProviderService == null) { + parameterProviderService = factoryProvider.createProviderParameter(parameterBackend); + + if (parameterProviderService == null) { + throw new MALException("The Parameter service provider was not created!"); + } + + SingleConnectionDetails details = parameterProviderService.getConnection().getConnectionDetails(); + parameterConsumerStub = factoryConsumer.createConsumerStubParameter(details); + } + } catch (InstantiationException ex) { + Logger.getLogger(SetUpProvidersAndConsumers.class.getName()).log(Level.SEVERE, null, ex); + } catch (IllegalAccessException ex) { + Logger.getLogger(SetUpProvidersAndConsumers.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotFoundException ex) { + Logger.getLogger(SetUpProvidersAndConsumers.class.getName()).log(Level.SEVERE, null, ex); + } catch (MALException ex) { + Logger.getLogger(SetUpProvidersAndConsumers.class.getName()).log(Level.SEVERE, null, ex); + } + } + public ActionInheritanceSkeleton getActionProvider() { return actionProviderService; } diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ActionBasicDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ActionBasicDataset.java new file mode 100644 index 000000000..09f651ea4 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ActionBasicDataset.java @@ -0,0 +1,90 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mc.ActionDataset; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ActionDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * ActionBasicDataset implements the dataset #AC-1. + */ +public class ActionBasicDataset extends ActionDataset { + + public static final ObjectRef sat1ChgTAbsValRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ActionDefinition.TYPE_ID.getTypeId(), + Constant.ID_CHGTABSVAL, + new UInteger(1)); + + public ActionBasicDataset() { + // build ArgumentDefinition objects + + // ArgumentDefinition + // - argId: "GENE_AR_TIMEABSVAL" + // - description: "absolute time in seconds" + // - type: TIME + // - unit="s" + ArgumentDefinition argDefTimeAbsVal = + new ArgumentDefinition( + Constant.ID_TIMEABSVAL, + "absolute time in seconds", + AttributeType.TIME, + "s"); + + // build ActionDefinition objects + + // ActionDefinition + // - identity: ("fr.cnes.mission.sat1", "SAT_TC_CHGTABSVAL", version=1) + // - description: "TC 9.128 – CHANGE_ONBOARD_TIME_ABSOLUTE_VALUE" + // - category: DEFAULT + // - progressStepCount: 0 + // - arguments: { "GENE_AR_TIMEABSVAL" } + addAction( + new ObjectIdentity( + sat1ChgTAbsValRef.getDomain(), + sat1ChgTAbsValRef.getKey(), + sat1ChgTAbsValRef.getObjectVersion()), + new String("TC 9.128 – CHANGE_ONBOARD_TIME_ABSOLUTE_VALUE"), + ActionCategory.DEFAULT, + new UShort(0), + new ArgumentDefinitionList(new ArrayList<> (Arrays.asList(argDefTimeAbsVal)))); + } + + // use default check function from base class + // use default execute function from base class +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ActionDefaultDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ActionDefaultDataset.java new file mode 100644 index 000000000..1454e3129 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ActionDefaultDataset.java @@ -0,0 +1,300 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * System : ESA CCSDS MO Services + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; + +import org.ccsds.mo.mc.testbed.Constant; +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mc.ActionDataset; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ActionDefinition; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; + +/** + * ActionBasicDataset implements the dataset #AC-2. + */ +public class ActionDefaultDataset extends ActionDataset { + + public static final ObjectRef sat1ChgTAbsValRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ActionDefinition.TYPE_ID.getTypeId(), + Constant.ID_CHGTABSVAL, + new UInteger(1)); + public static final ObjectRef sat2ChgTAbsValRef = + new ObjectRef<>( + Constant.DOMAIN_SAT2, + ActionDefinition.TYPE_ID.getTypeId(), + Constant.ID_CHGTABSVAL, + new UInteger(1)); + public static final ObjectRef sat1DefAttitude1Ref = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ActionDefinition.TYPE_ID.getTypeId(), + Constant.ID_DEFATTITUDE, + new UInteger(1)); + public static final ObjectRef sat1DefAttitude2Ref = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ActionDefinition.TYPE_ID.getTypeId(), + Constant.ID_DEFATTITUDE, + new UInteger(2)); + + public ActionDefaultDataset() { + // build ArgumentDefinition objects + + // ArgumentDefinition + // - argId: "GENE_AR_TIMEABSVAL" + // - description: "absolute time in seconds" + // - type: TIME + // - unit="s" + ArgumentDefinition argDefTimeAbsVal = + new ArgumentDefinition( + Constant.ID_TIMEABSVAL, + "absolute time in seconds", + AttributeType.TIME, + "s"); + + // ArgumentDefinition + // - argId: "GENE_AR_STARTTIME" + // - description: "Parameter GENE_AR_Z0427" + // - type: DOUBLE + // - unit=null + ArgumentDefinition argDefStartTime = + new ArgumentDefinition( + Constant.ID_STARTTIME, + "Parameter GENE_AR_Z0427", + AttributeType.DOUBLE, + null); + + // ArgumentDefinition + // - argId: "GENE_AR_DURATION" + // - description: "Parameter GENE_AR_Z0481" + // - type: DOUBLE + // - unit=null + ArgumentDefinition argDefDuration = + new ArgumentDefinition( + Constant.ID_DURATION, + "Parameter GENE_AR_Z0481", + AttributeType.DOUBLE, + null); + + // ArgumentDefinition + // - argId: "GENE_AR_MANEUVTYPE" + // - description: "Parameter GENE_AR_Z0584" + // - type: STRING + // - unit=null + ArgumentDefinition argDefManeuvType = + new ArgumentDefinition( + Constant.ID_MANEUVTYPE, + "Parameter GENE_AR_Z0584", + AttributeType.STRING, + null); + + // ArgumentDefinition + // - argId: "GENE_AR_POLYNOMDEG" + // - description: "" + // - type: ULONG + // - unit=null + ArgumentDefinition argDefTimePolyNomDeg = + new ArgumentDefinition( + Constant.ID_POLYNOMDEG, + "", + AttributeType.ULONG, + null); + + // ArgumentDefinition + // - argId: "GENE_AR_POLVALUE" + // - description: "" + // - type: DOUBLE + // - unit=null + ArgumentDefinition argDefPolValue = + new ArgumentDefinition( + Constant.ID_POLVALUE, + "", + AttributeType.DOUBLE, + null); + + // build ActionDefinition objects + + // ActionDefinition + // - identity: ("fr.cnes.mission.sat1", "SAT_TC_CHGTABSVAL", version=1) + // - description: "TC 9.128 – CHANGE_ONBOARD_TIME_ABSOLUTE_VALUE" + // - category: DEFAULT + // - progressStepCount: 0 + // - arguments: { "GENE_AR_TIMEABSVAL" } + addAction( + new ObjectIdentity( + sat1ChgTAbsValRef.getDomain(), + sat1ChgTAbsValRef.getKey(), + sat1ChgTAbsValRef.getObjectVersion()), + new String("TC 9.128 – CHANGE_ONBOARD_TIME_ABSOLUTE_VALUE"), + ActionCategory.DEFAULT, + new UShort(0), + new ArgumentDefinitionList(new ArrayList<> (Arrays.asList(argDefTimeAbsVal)))); + + // ActionDefinition + // - identity: ("fr.cnes.mission.sat2", "SAT_TC_CHGTABSVAL", version=1) + // - description: "TC 9.128 – CHANGE_ONBOARD_TIME_ABSOLUTE_VALUE" + // - category: DEFAULT + // - progressStepCount: 0 + // - arguments: { "GENE_AR_TIMEABSVAL" } + addAction( + new ObjectIdentity( + sat2ChgTAbsValRef.getDomain(), + sat2ChgTAbsValRef.getKey(), + sat2ChgTAbsValRef.getObjectVersion()), + new String("TC 9.128 – CHANGE_ONBOARD_TIME_ABSOLUTE_VALUE"), + ActionCategory.DEFAULT, + new UShort(0), + new ArgumentDefinitionList(new ArrayList<> (Arrays.asList(argDefTimeAbsVal)))); + + // ActionDefinition + // - identity: ("fr.cnes.mission.sat1", "MIS_TC_DEFATTITUDE", version=1) + // - description: "Change the satellite attitude – Deprecated" + // - category: DEFAULT + // - progressStepCount: 3 + // - arguments: null + addAction( + new ObjectIdentity( + sat1DefAttitude1Ref.getDomain(), + sat1DefAttitude1Ref.getKey(), + sat1DefAttitude1Ref.getObjectVersion()), + new String("Change the satellite attitude – Deprecated"), + ActionCategory.DEFAULT, + new UShort(3), + null); + + // ActionDefinition + // - identity: ("fr.cnes.mission.sat1", "MIS_TC_DEFATTITUDE", version=2) + // - description: "Change the satellite attitude" + // - category: DEFAULT + // - progressStepCount: 3 + // - arguments: { "GENE_AR_STARTTIME", "GENE_AR_DURATION", "GENE_AR_MANEUVTYPE", "GENE_AR_POLYNOMDEG", "GENE_AR_POLVALUE", "GENE_AR_POLVALUE", "GENE_AR_POLVALUE" } + addAction( + new ObjectIdentity( + sat1DefAttitude2Ref.getDomain(), + sat1DefAttitude2Ref.getKey(), + sat1DefAttitude2Ref.getObjectVersion()), + new String("Change the satellite attitude"), + ActionCategory.DEFAULT, + new UShort(3), + new ArgumentDefinitionList(new ArrayList<>(Arrays.asList( + argDefStartTime, argDefDuration, argDefManeuvType, argDefTimePolyNomDeg, + argDefPolValue, argDefPolValue, argDefPolValue)))); + } + + private boolean skipNextCall = false; + private final HashMap requestLatchMap = new HashMap(); + + @Override + public String check(ActionExecutionRequest executionRequest, ActionDefinition definition) { + if (skipNextCall) { + skipNextCall = false; + return Constant.STR_SKIPPED; + } + + if (!Constant.ID_DEFATTITUDE.equals(definition.getObjectIdentity().getKey()) || + definition.getObjectIdentity().getVersion().getValue() != 2) + return null; + + // GENE_AR_MANEUVTYPE is the third argument, index 2 + NullableAttribute argManeuvTypeNA = executionRequest.getArgumentValues().get(2); + if (argManeuvTypeNA == null) + return "Invalid value for argument " + Constant.ID_MANEUVTYPE + ": null"; + String maneuvType = argManeuvTypeNA.getValue().attribute2string(); + if (Constant.STR_OK.equals(maneuvType) || + Constant.STR_STEPS.equals(maneuvType) || + Constant.STR_SKIP.equals(maneuvType) || + Constant.STR_WAIT.equals(maneuvType) || + Constant.STR_FAIL2.equals(maneuvType)) { + return null; + } else { + return "Invalid value for argument " + Constant.ID_MANEUVTYPE + ": " + maneuvType; + } + } + + @Override + public boolean execute(ActionExecutionRequest executionRequest, ActionDefinition definition, ExecuteListener listener) { + // The Action MIS_TC_DEFATTITUDE shall be implemented by the test provider with specific test behaviors related to the value of its arguments: + // - GENE_AR_MANEUVTYPE="ok" → complete successfully + // - GENE_AR_MANEUVTYPE="steps"→ complete GENE_AR_POLYNOMDEG steps, then fails + // - GENE_AR_MANEUVTYPE="skip"→ fails next call with error code Rejected and extraInfo "skipped" + // - GENE_AR_MANEUVTYPE="wait"→ wait for a MCPrototype:ActionTest:resumeAction call after sending the first ActionInProgressEvent + // - GENE_AR_MANEUVTYPE="fail-2"→ fails after sending a first successful ActionInProgressEvent + // - GENE_AR_MANEUVTYPE=any else → error Rejected + if (!Constant.ID_DEFATTITUDE.equals(definition.getObjectIdentity().getKey()) || + definition.getObjectIdentity().getVersion().getValue() != 2) + return super.execute(executionRequest, definition, listener); + + // GENE_AR_MANEUVTYPE is the third argument, index 2 + String maneuvType = executionRequest.getArgumentValues().get(2).getValue().attribute2string(); + if (Constant.STR_OK.equals(maneuvType)) { + return super.execute(executionRequest, definition, listener); + } else if (Constant.STR_STEPS.equals(maneuvType)) { + // GENE_AR_POLYNOMDEG is the 4th argument, index 3 + int progressStepCount = ((Union) executionRequest.getArgumentValues().get(3).getValue()).getLongValue().intValue(); + for (int i=0; i sat1BcMtq1Ref = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1, + new UInteger(1)); + public final int sat1BcMtq1AdId; + + public AggregationBasicDataset( + BackendTimer timer, + SingleConnectionDetails parameterConnectionDetails) { + super(timer, parameterConnectionDetails); + + // build AggregationDefinition objects + + // AggregationDefinition + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} } + // Default Report Configuration + // - reportingEnabled: true + // - reportInterval: 301s + sat1BcMtq1AdId = + addAggregation( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1)), + new String(""), + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterBasicDataset.sat1Mtq1VoltageRef))), + new DefaultReportConfiguration(true, 301*1000)); + + } + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDatasetForReportConfig.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDatasetForReportConfig.java new file mode 100755 index 000000000..1fe2962b4 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDatasetForReportConfig.java @@ -0,0 +1,127 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.ObjectRefList; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mc.ActionDataset; +import org.ccsds.moims.mo.mc.AggregationDataset; +import org.ccsds.moims.mo.mc.ParameterDataset; +import org.ccsds.moims.mo.mc.backends.BackendTimer; +import org.ccsds.moims.mo.mc.backends.ConversionFunction; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.AggregationDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * AggregationDatasetForReportConfig implements the dataset #AG-3. + */ +public class AggregationDatasetForReportConfig extends AggregationDataset { + + public static final ObjectRef sat1BcMtq1Ref = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1, + new UInteger(1)); + public final int sat1BcMtq1AdId; + + public static final ObjectRef sat1BcMtq1RevRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1_REV, + new UInteger(1)); + public final int sat1BcMtq1RevAdId; + + public AggregationDatasetForReportConfig(BackendTimer timer, SingleConnectionDetails parameterConnectionDetails) { + super(timer, parameterConnectionDetails); + + // build AggregationDefinition objects + + // AggregationDefinition + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1}} + // Default Report Configuration + // - reportingEnabled: true + // - reportInterval: 301s + sat1BcMtq1AdId = + addAggregation( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1)), + new String(""), + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDefaultDataset.sat1Mtq1VoltageRef, + ParameterDefaultDataset.sat1Mtq1EnabledRef))), + new DefaultReportConfiguration(true, 301*1000)); + + // AggregationDefinition + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}} + // Default Report Configuration + // - reportingEnabled: false + // - reportInterval: 301s + sat1BcMtq1RevAdId = + addAggregation( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1)), + new String(""), + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + ParameterDefaultDataset.sat1Mtq1VoltageRef))), + new DefaultReportConfiguration(false, 301*1000)); + + } + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDefaultDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDefaultDataset.java new file mode 100755 index 000000000..ee7aa9dd4 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDefaultDataset.java @@ -0,0 +1,96 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.ObjectRefList; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mc.ActionDataset; +import org.ccsds.moims.mo.mc.AggregationDataset; +import org.ccsds.moims.mo.mc.ParameterDataset; +import org.ccsds.moims.mo.mc.backends.BackendTimer; +import org.ccsds.moims.mo.mc.backends.ConversionFunction; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.AggregationDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * AggregationDefaultDataset implements the dataset #AG-2. + */ +public class AggregationDefaultDataset extends AggregationDataset { + + public static final ObjectRef sat1BcMtq1Ref = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1, + new UInteger(1)); + public final int sat1BcMtq1AdId; + + public AggregationDefaultDataset(BackendTimer timer, SingleConnectionDetails parameterConnectionDetails) { + super(timer, parameterConnectionDetails); + + // build AggregationDefinition objects + + // AggregationDefinition + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1}} + // Default Report Configuration + // - reportingEnabled: true + // - reportInterval: 301s + sat1BcMtq1AdId = + addAggregation( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1)), + new String(""), + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDefaultDataset.sat1Mtq1VoltageRef, + ParameterDefaultDataset.sat1Mtq1EnabledRef))), + new DefaultReportConfiguration(true, 301*1000)); + + } + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDynamicDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDynamicDataset.java new file mode 100755 index 000000000..6dfc18ebb --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationDynamicDataset.java @@ -0,0 +1,98 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.ObjectRefList; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mc.ActionDataset; +import org.ccsds.moims.mo.mc.AggregationDataset; +import org.ccsds.moims.mo.mc.ParameterDataset; +import org.ccsds.moims.mo.mc.backends.BackendTimer; +import org.ccsds.moims.mo.mc.backends.ConversionFunction; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.AggregationDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * AggregationDynamicDataset implements the dataset #AG-4. + */ +public class AggregationDynamicDataset extends AggregationDataset { + + public static final ObjectRef sat1BcMtq1Ref = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1, + new UInteger(1)); + public final int sat1BcMtq1AdId; + + public AggregationDynamicDataset(BackendTimer timer, SingleConnectionDetails parameterConnectionDetails) { + super(timer, parameterConnectionDetails); + + // build AggregationDefinition objects + + // AggregationDefinition + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1}} + // Default Report Configuration + // - reportingEnabled: true + // - reportInterval: 120s + sat1BcMtq1AdId = + addAggregation( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1)), + new String(""), + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDatasetForReportConfig.sat1Mtq1VoltageRef, + ParameterDatasetForReportConfig.sat1Mtq1EnabledRef))), + new DefaultReportConfiguration(true, 301*1000)); + + // default report interval for the provider is 120s + addDefaultReportConfig(new DefaultReportConfiguration(true, 120*1000)); + } + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationErrorDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationErrorDataset.java new file mode 100755 index 000000000..a809b8c3d --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AggregationErrorDataset.java @@ -0,0 +1,163 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.ObjectRefList; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mc.ActionDataset; +import org.ccsds.moims.mo.mc.AggregationDataset; +import org.ccsds.moims.mo.mc.ParameterDataset; +import org.ccsds.moims.mo.mc.backends.BackendTimer; +import org.ccsds.moims.mo.mc.backends.ConversionFunction; +import org.ccsds.moims.mo.mc.backends.AggregationBackend.DefaultReportConfiguration; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.AggregationDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * AggregationErrorDataset implements the dataset #AG-9. + */ +public class AggregationErrorDataset extends AggregationDataset { + + public static final ObjectRef sat1BcMtq1Ref = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1, + new UInteger(1)); + public final int sat1BcMtq1AdId; + + public static final ObjectRef sat1BcMtq1RevRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1_REV, + new UInteger(1)); + public final int sat1BcMtq1RevAdId; + + public static final ObjectRef sat2BcMtq1Ref = + new ObjectRef<>( + Constant.DOMAIN_SAT2, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1, + new UInteger(1)); + public final int sat2BcMtq1AdId; + + public AggregationErrorDataset(BackendTimer timer, SingleConnectionDetails parameterConnectionDetails) { + super(timer, parameterConnectionDetails); + + // build AggregationDefinition objects + + // AggregationDefinition + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1}} + // Default Report Configuration + // - reportingEnabled: true + // - reportInterval: 301s + sat1BcMtq1AdId = + addAggregation( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1)), + new String(""), + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDefaultDataset.sat1Mtq1VoltageRef, + ParameterDefaultDataset.sat1Mtq1EnabledRef))), + new DefaultReportConfiguration(true, 301*1000)); + + // AggregationDefinition + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}} + // Default Report Configuration + // - reportingEnabled: false + // - reportInterval: 301s + sat1BcMtq1RevAdId = + addAggregation( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1)), + new String(""), + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + ParameterDefaultDataset.sat1Mtq1VoltageRef))), + new DefaultReportConfiguration(false, 301*1000)); + + // AggregationDefinition + // - identity: ("fr.cnes.mission.sat2", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} + // -- {domain="fr.cnes.mission.sat2", key="ATT_BC_MTQ1VOLTAGE", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1}} + // Default Report Configuration + // - reportingEnabled: false + // - reportInterval: 301s + sat2BcMtq1AdId = + addAggregation( + new ObjectIdentity( + Constant.DOMAIN_SAT2, + Constant.ID_BC_MTQ1, + new UInteger(1)), + new String(""), + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterErrorDataset.sat1Mtq1VoltageRef, + ParameterErrorDataset.sat2Mtq1VoltageRef, + ParameterErrorDataset.sat1Mtq1EnabledRef))), + new DefaultReportConfiguration(false, 301*1000)); + + // default report interval for the provider is 120s + addDefaultReportConfig(new DefaultReportConfiguration(true, 120*1000)); + } + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertBasicDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertBasicDataset.java new file mode 100755 index 000000000..af06a3bb6 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertBasicDataset.java @@ -0,0 +1,87 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mc.AlertDataset; +import org.ccsds.moims.mo.mc.structures.AlertDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.Severity; +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * AlertBasicDataset implements the dataset #AL-1. + */ +public class AlertBasicDataset extends AlertDataset { + + public static final ObjectRef sat1Mtq1VoltageHighRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AlertDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1)); + public final int sat1Mtq1VoltageHighAdId; + + public AlertBasicDataset() { + // build ArgumentDefinition objects + + // ArgumentDefinition + // - argId: "MTQ1VOLTAGE_HIGH_VAL" + // - description: "value of exceeding voltage" + // - type: DOUBLE + // - unit="V" + ArgumentDefinition argDefVoltageHighVal = + new ArgumentDefinition( + Constant.ID_MTQ1VOLTAGE_HIGH_VAL, + "value of exceeding voltage", + AttributeType.DOUBLE, + "V"); + + // build AlertDefinition objects + + // AlertDefinition + // - identity: ("fr.cnes.mission.sat1", "MTQ1VOLTAGE_HIGH", version=1) + // - description: "" + // - severity: SEVERE + // - arguments: { "MTQ1VOLTAGE_HIGH_VAL" } + sat1Mtq1VoltageHighAdId = + addAlert( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1)), + new String(""), + Severity.SEVERE, + new ArgumentDefinitionList(new ArrayList<> (Arrays.asList(argDefVoltageHighVal)))); + } + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertDefaultDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertDefaultDataset.java new file mode 100755 index 000000000..0a3c2b561 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertDefaultDataset.java @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mc.AlertDataset; +import org.ccsds.moims.mo.mc.structures.AlertDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.Severity; +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * AlertDefaultDataset implements the dataset #AL-2. + */ +public class AlertDefaultDataset extends AlertDataset { + + public static final ObjectRef sat1Mtq1VoltageHighRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AlertDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1)); + public final int sat1Mtq1VoltageHighAdId; + public static final ObjectRef sat1Mtq1VoltageLowRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AlertDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1VOLTAGE_LOW, + new UInteger(1)); + public final int sat1Mtq1VoltageLowAdId; + + public AlertDefaultDataset() { + // build ArgumentDefinition objects + + // ArgumentDefinition + // - argId: "MTQ1VOLTAGE_HIGH_VAL" + // - description: "value of exceeding voltage" + // - type: DOUBLE + // - unit="V" + ArgumentDefinition argDefVoltageHighVal = + new ArgumentDefinition( + Constant.ID_MTQ1VOLTAGE_HIGH_VAL, + "value of exceeding voltage", + AttributeType.DOUBLE, + "V"); + + // build AlertDefinition objects + + // AlertDefinition + // - identity: ("fr.cnes.mission.sat1", "MTQ1VOLTAGE_HIGH", version=1) + // - description: "" + // - severity: SEVERE + // - arguments: { "MTQ1VOLTAGE_HIGH_VAL" } + sat1Mtq1VoltageHighAdId = + addAlert( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1)), + new String(""), + Severity.SEVERE, + new ArgumentDefinitionList(new ArrayList<> (Arrays.asList(argDefVoltageHighVal)))); + + // AlertDefinition + // - identity: ("fr.cnes.mission.sat1", "MTQ1VOLTAGE_LOW", version=1) + // - description: "" + // - severity: SEVERE + // - arguments: { "MTQ1VOLTAGE_HIGH_VAL" } + sat1Mtq1VoltageLowAdId = + addAlert( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE_LOW, + new UInteger(1)), + new String(""), + Severity.SEVERE, + new ArgumentDefinitionList(new ArrayList<> (Arrays.asList(argDefVoltageHighVal)))); + } + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertErrorDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertErrorDataset.java new file mode 100755 index 000000000..9e8ec8c3c --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/AlertErrorDataset.java @@ -0,0 +1,110 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mc.AlertDataset; +import org.ccsds.moims.mo.mc.structures.AlertDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.Severity; +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * AlertErrorDataset implements the dataset #AL-9. + */ +public class AlertErrorDataset extends AlertDataset { + + public static final ObjectRef sat1Mtq1VoltageHighRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AlertDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1)); + public final int sat1Mtq1VoltageHighAdId; + + public static final ObjectRef sat2Mtq1VoltageHighRef = + new ObjectRef<>( + Constant.DOMAIN_SAT2, + AlertDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1)); + public final int sat2Mtq1VoltageHighAdId; + + public AlertErrorDataset() { + // build ArgumentDefinition objects + + // ArgumentDefinition + // - argId: "MTQ1VOLTAGE_HIGH_VAL" + // - description: "value of exceeding voltage" + // - type: DOUBLE + // - unit="V" + ArgumentDefinition argDefVoltageHighVal = + new ArgumentDefinition( + Constant.ID_MTQ1VOLTAGE_HIGH_VAL, + "value of exceeding voltage", + AttributeType.DOUBLE, + "V"); + + // build AlertDefinition objects + + // AlertDefinition + // - identity: ("fr.cnes.mission.sat1", "MTQ1VOLTAGE_HIGH", version=1) + // - description: "" + // - severity: SEVERE + // - arguments: { "MTQ1VOLTAGE_HIGH_VAL" } + sat1Mtq1VoltageHighAdId = + addAlert( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1)), + new String(""), + Severity.SEVERE, + new ArgumentDefinitionList(new ArrayList<> (Arrays.asList(argDefVoltageHighVal)))); + + // AlertDefinition + // - identity: ("fr.cnes.mission.sat2", "MTQ1VOLTAGE_HIGH", version=1) + // - description: "" + // - severity: SEVERE + // - arguments: { "MTQ1VOLTAGE_HIGH_VAL" } + sat2Mtq1VoltageHighAdId = + addAlert( + new ObjectIdentity( + Constant.DOMAIN_SAT2, + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1)), + new String(""), + Severity.SEVERE, + new ArgumentDefinitionList(new ArrayList<> (Arrays.asList(argDefVoltageHighVal)))); + } + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/BackendTimerImpl.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/BackendTimerImpl.java new file mode 100755 index 000000000..761cd5f62 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/BackendTimerImpl.java @@ -0,0 +1,209 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : ESA CCSDS MO Services + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledFuture; +import java.util.logging.Logger; + +import org.ccsds.moims.mo.mc.backends.BackendTimer; + +public class BackendTimerImpl implements BackendTimer { + + static final Logger logger = Logger.getLogger(BackendTimerImpl.class.getName()); + + long origin; + long now; + long target; + boolean running = false; + boolean skipping = false; + + private class Schedule { + long wakeUp; + Runnable task; + public Schedule(long wakeUp, Runnable task) { + this.wakeUp = wakeUp; + this.task = task; + } + public Schedule(long wakeUp) { + this(wakeUp, null); + } + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("{ wakeUp=").append(wakeUp); + builder.append(", task=").append(task); + return builder.toString(); + } + } + // must be accessed with lock on this BackendTimer object + private final LinkedList schedules = new LinkedList<>(); + + // must be accessed with lock on this BackendTimer object + private final Set> runningTasks = new HashSet<>(); + + public BackendTimerImpl() {} + + public BackendTimerImpl(long origin) { + logger.info("new backend timer, origin=" + origin); + init(origin); + } + + @Override + public void init(long origin) { + this.origin = origin; + now = origin; + target = now; + running = true; + } + + @Override + public void stop() { + + } + + @Override + public long currentTimeMillis() { + return now; + } + + @Override + public void sleep(long millis) + throws InterruptedException { + if (millis <= 0) + return; + long wakeUp = now + millis; + synchronized(this) { + addSchedule(wakeUp); + while (running && now < wakeUp) + wait(); + if (!running) + logger.info("exit sleep, timer not running"); + } + } + + @Override + public void schedule(Runnable command, ExecutorService executor, long delay) + throws RejectedExecutionException, NullPointerException { + if (delay <= 0) { + Future task = executor.submit(command); + // synchronize with task execution completion + try { + task.get(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } else { + long wakeUp = now + delay; + Schedule schedule = new Schedule(wakeUp, + () -> { + Future task = executor.submit(command); + // synchronize with task execution completion + try { + task.get(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }); + synchronized(this) { + addSchedule(schedule); + } + } + } + + private void addSchedule(long wakeUp) { + Schedule schedule = new Schedule(wakeUp); + addSchedule(schedule); + } + private void addSchedule(Schedule schedule) { + logger.info("schedule=" + schedule); + int index = 0; + long wakeUp = schedule.wakeUp; + while (index < schedules.size()) { + Schedule next = schedules.get(index); + long nextTime = next.wakeUp; + if (wakeUp < nextTime) + break; + if (wakeUp == nextTime && schedule.task == null && next.task == null) + return; + index++; + } + logger.info("add schedule at index=" + index); + schedules.add(index, schedule); + } + + /** + * Updates virtual time, and trigger all necessary executions. + * @param delay time increase in milliseconds + */ + public void skip(long delay) { + logger.info("now=" + now + ", delay=" + delay); + synchronized(this) { + if (skipping) { + logger.warning("should not call skip while skipping"); + long newTarget = now + delay; + if (newTarget > target) + target = newTarget; + return; + } + skipping = true; + target = now + delay; + } + while (skipping) { + Schedule next = null; + synchronized(this) { + if (!schedules.isEmpty()) + next = schedules.getFirst(); + if (next == null || target < next.wakeUp) { + now = target; + skipping = false; + return; + } + now = next.wakeUp; + schedules.removeFirst(); + } + if (next.task != null) { + logger.info("execute task at " + now); + next.task.run(); + } else { + synchronized(this) { + logger.info("notify waiting task at " + now); + notifyAll(); + } + } + // give some time for the asynchronous consequences to take place + // before skipping time again + try { Thread.sleep(10); } catch (Exception e) {} + } + } +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/FifteenProductsDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/FifteenProductsDataset.java deleted file mode 100644 index 67d81e579..000000000 --- a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/FifteenProductsDataset.java +++ /dev/null @@ -1,57 +0,0 @@ -/* ---------------------------------------------------------------------------- - * Copyright (C) 2024 European Space Agency - * European Space Operations Centre - * Darmstadt - * Germany - * ---------------------------------------------------------------------------- - * System : ESA CCSDS MO Services - * ---------------------------------------------------------------------------- - * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 - * You may not use this file except in compliance with the License. - * - * Except as expressly set forth in this License, the Software is provided to - * You on an "as is" basis and without warranties of any kind, including without - * limitation merchantability, fitness for a particular purpose, absence of - * defects or errors, accuracy or non-infringement of intellectual property rights. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * ---------------------------------------------------------------------------- - */ -package org.ccsds.mo.mc.testbed.backends; - -import org.ccsds.moims.mo.mal.structures.Blob; -import org.ccsds.moims.mo.mal.structures.Identifier; -import org.ccsds.moims.mo.mal.structures.IdentifierList; -import org.ccsds.moims.mo.mal.structures.ObjectRef; -import org.ccsds.moims.mo.mc.ParameterDataset; -import org.ccsds.moims.mo.mc.structures.ParameterDefinition; - -/** - * A dummy backend in order to try out the provider. - */ -public class FifteenProductsDataset extends ParameterDataset { - - public ObjectRef ref; - - public FifteenProductsDataset() { - IdentifierList domain = new IdentifierList(); - domain.add(new Identifier("myDomain")); - - // --------------------------------------------------- - // Product Types - // --------------------------------------------------- - //ProductType type1 = new ProductType(new Identifier("type1")); - // --------------------------------------------------- - // Products - // --------------------------------------------------- - for (int i = 0; i < 15; i++) { - Identifier name = new Identifier("product_" + i); - //ref = new ObjectRef(domain, Product.TYPE_ID.getTypeId(), name, new UInteger(1)); - Blob productBody = new Blob(); - //ProductMetadata metadata = new ProductMetadata(type1, ref, Time.now(), timeWindow); - //super.addNewProduct(ref, productBody, metadata); - } - } - -} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/OneProductDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/PacketBasicDataset.java old mode 100644 new mode 100755 similarity index 50% rename from testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/OneProductDataset.java rename to testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/PacketBasicDataset.java index 79700da06..bb66891df --- a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/OneProductDataset.java +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/PacketBasicDataset.java @@ -4,7 +4,11 @@ * Darmstadt * Germany * ---------------------------------------------------------------------------- - * System : ESA CCSDS MO Services + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C * ---------------------------------------------------------------------------- * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 * You may not use this file except in compliance with the License. @@ -20,35 +24,24 @@ */ package org.ccsds.mo.mc.testbed.backends; +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.AttributeTypeList; import org.ccsds.moims.mo.mal.structures.Identifier; import org.ccsds.moims.mo.mal.structures.IdentifierList; -import org.ccsds.moims.mo.mal.structures.ObjectRef; -import org.ccsds.moims.mo.mc.ParameterDataset; -import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.PacketDataset; +import java.util.ArrayList; +import java.util.Arrays; /** - * A dummy backend in order to try out the provider. + * PacketBasicDataset implements the dataset #PK-1. */ -public class OneProductDataset extends ParameterDataset { - - public ObjectRef ref; - - public OneProductDataset() { - IdentifierList domain = new IdentifierList(); - domain.add(new Identifier("myDomain")); +public class PacketBasicDataset extends PacketDataset { - // --------------------------------------------------- - // Product Types - // --------------------------------------------------- - //ProductType type1 = new ProductType(new Identifier("type1")); - // --------------------------------------------------- - // Products - // --------------------------------------------------- - //TimeWindow timeWindow = new TimeWindow(Time.now(), Time.now()); - //ref = new ObjectRef(domain, Product.TYPE_ID.getTypeId(), new Identifier("key1"), new UInteger(1)); - //Blob productBody = new Blob(); - //ProductMetadata metadata = new ProductMetadata(type1, ref, Time.now(), timeWindow); - //super.addNewProduct(ref, productBody, metadata); - } + public PacketBasicDataset() { + // define the custom subscription keys + setCustomSubscriptionKeys( + new IdentifierList(new ArrayList<>(Arrays.asList(new Identifier("destID")))), + new AttributeTypeList(new ArrayList<>(Arrays.asList(AttributeType.UOCTET)))); + } } diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterBasicDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterBasicDataset.java new file mode 100755 index 000000000..2d93d9134 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterBasicDataset.java @@ -0,0 +1,101 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mc.ActionDataset; +import org.ccsds.moims.mo.mc.ParameterDataset; +import org.ccsds.moims.mo.mc.backends.BackendTimer; +import org.ccsds.moims.mo.mc.backends.ConversionFunction; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * ParameterBasicDataset implements the dataset #PA-1. + */ +public class ParameterBasicDataset extends ParameterDataset { + + public static final ObjectRef sat1Mtq1VoltageRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ParameterDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1VOLTAGE, + new UInteger(1)); + public final int sat1Mtq1VoltagePdId; + + public ParameterBasicDataset(BackendTimer timer) { + super(timer); + + // build ParameterDefinition objects + + // ParameterDefinition + // - identity: ("fr.cnes.mission.sat1", "ATT_BC_MTQ1VOLTAGE", version=1) + // - description: "" + // - rawType: DOUBLE + // - rawUnit: "V" + // - convertedType: null + // - convertedUnit: null + // Default Report Configuration + // - reportingEnabled: true + // - reportInterval: 300s (minimum sampling interval=60s) + DefaultReportConfiguration config = new DefaultReportConfiguration(true, 300*1000, 60*1000); + sat1Mtq1VoltagePdId = + addParameter( + new ObjectIdentity( + sat1Mtq1VoltageRef.getDomain(), + sat1Mtq1VoltageRef.getKey(), + sat1Mtq1VoltageRef.getObjectVersion()), + new String("absolute time in seconds"), + AttributeType.DOUBLE, + new String("V"), + null, null, + config, + ParameterDataset::noConversionFunction, + false); + + // register all values + // at this time, the timer must have been initialized to the time origin + long timeOrigin = timer.currentTimeMillis(); + + // paramRef.domain paramRef.key timestamp samplingTime rawValue + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:00:10 0:00:00 12.00 + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+10000, timeOrigin, new Union(new Double(12.00))); + } + +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDatasetForReportConfig.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDatasetForReportConfig.java new file mode 100755 index 000000000..d47f684b2 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDatasetForReportConfig.java @@ -0,0 +1,60 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mc.backends.BackendTimer; + +/** + * ParameterDatasetForReportConfig implements the dataset #PA-3. + * Definitions are retrieved from ParameterDefaultDataset. + */ +public class ParameterDatasetForReportConfig extends ParameterDefaultDataset { + + public ParameterDatasetForReportConfig(BackendTimer timer) { + super(timer); + } + + @Override + void addValues() { + // at this time, the timer must have been initialized to the time origin + long timeOrigin = timer.currentTimeMillis(); + + // paramRef.domain paramRef.key timestamp samplingTime rawValue + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:00:10 0:00:00 12.00 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1ENABLED" 0:00:10 0:00:00 1 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:05:10 0:05:00 12.05 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:10:10 0:10:00 12.10 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:15:10 0:15:00 12.15 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:20:10 0:20:00 12.20 + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+10*1000, timeOrigin, new Union(new Double(12.00))); + addParameterValue(sat1Mtq1EnabledPdId, timeOrigin+10*1000, timeOrigin, new UInteger(1)); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((5*60)+10)*1000, timeOrigin+5*60*1000, new Union(new Double(12.05))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((10*60)+10)*1000, timeOrigin+10*60*1000, new Union(new Double(12.10))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((15*60)+10)*1000, timeOrigin+15*60*1000, new Union(new Double(12.15))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((20*60)+10)*1000, timeOrigin+20*60*1000, new Union(new Double(12.20))); + } +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDatasetForValidityState.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDatasetForValidityState.java new file mode 100755 index 000000000..b76fd2c86 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDatasetForValidityState.java @@ -0,0 +1,93 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.mo.mc.testbed.Constant; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mc.backends.BackendTimer; +import org.ccsds.moims.mo.mc.backends.ParameterBackend.ParameterRawValue; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ValidityState; + +/** + * ParameterDatasetForValidityState implements the dataset #PA-4. + * Definitions are retrieved from ParameterDefaultDataset. + */ +public class ParameterDatasetForValidityState extends ParameterDefaultDataset { + + public ParameterDatasetForValidityState(BackendTimer timer) { + super(timer, ParameterDatasetForValidityState::mtq1EnabledConversionFunction); + } + + @Override + void addValues() { + // at this time, the timer must have been initialized to the time origin + long timeOrigin = timer.currentTimeMillis(); + + // paramRef.domain paramRef.key timestamp samplingTime rawValue + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1ENABLED" 0:00:10 0:00:00 null + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1ENABLED" 0:01:10 0:01:00 1 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1ENABLED" 0:13:10 0:13:00 8 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1ENABLED" 0:25:10 0:25:00 2 + addParameterValue(sat1Mtq1EnabledPdId, timeOrigin+10*1000, timeOrigin, null); + addParameterValue(sat1Mtq1EnabledPdId, timeOrigin+((1*60)+10)*1000, timeOrigin+1*60*1000, new UInteger(1)); + addParameterValue(sat1Mtq1EnabledPdId, timeOrigin+((13*60)+10)*1000, timeOrigin+13*60*1000, new UInteger(8)); + addParameterValue(sat1Mtq1EnabledPdId, timeOrigin+((25*60)+10)*1000, timeOrigin+25*60*1000, new UInteger(2)); + } + + /** + * Specific conversion function for the parameter ATT-BC-MTQ1ENABLED. + * - 0 → "DISABLED" + * - 1 → "ENABLED" + * - >1&<8 → valid value but fails conversion + * - >=8 → "UNKNOWN" (the raw value is considered invalid) + * Any value older that 10mn becomes EXPIRED + * + * @param parameterID + * @param rawValue + * @return + */ + public static ParameterValueData mtq1EnabledConversionFunction(int parameterID, ParameterRawValue rawValue) { + if (rawValue == null || rawValue.rawValue == null) + return new ParameterValueData(ValidityState.INVALID_RAW, null, null); + if (!(rawValue.rawValue instanceof UInteger)) + return new ParameterValueData(ValidityState.INVALID_CONVERSION, rawValue.rawValue, null); + long rawInt = ((UInteger) rawValue.rawValue).getValue(); + boolean expired = (rawValue.timestamp + 10*60*1000) < backendTimer.currentTimeMillis(); + if (rawInt == 0) + return new ParameterValueData( + expired ? ValidityState.EXPIRED : ValidityState.VALID, + rawValue.rawValue, Constant.AT_STRING_DISABLED); + if (rawInt == 1) + return new ParameterValueData( + expired ? ValidityState.EXPIRED : ValidityState.VALID, + rawValue.rawValue, Constant.AT_STRING_ENABLED); + if (rawInt < 8) + return new ParameterValueData(ValidityState.INVALID_CONVERSION, rawValue.rawValue, null); + return new ParameterValueData(ValidityState.INVALID, rawValue.rawValue, Constant.AT_STRING_UNKNOWN); + } +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDefaultDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDefaultDataset.java new file mode 100755 index 000000000..c4372eca6 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterDefaultDataset.java @@ -0,0 +1,190 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mc.ParameterDataset; +import org.ccsds.moims.mo.mc.backends.BackendTimer; +import org.ccsds.moims.mo.mc.backends.ConversionFunction; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ValidityState; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * ParameterDefaultDataset implements the dataset #PA-2. + */ +public class ParameterDefaultDataset extends ParameterDataset { + + public static final ObjectRef sat1Mtq1VoltageRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ParameterDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1VOLTAGE, + new UInteger(1)); + public final int sat1Mtq1VoltagePdId; + public static final ObjectRef sat1Mtq1EnabledRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ParameterDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1ENABLED, + new UInteger(1)); + public final int sat1Mtq1EnabledPdId; + + // the Mtq1Enabled conversion function requires access to the timer + public static BackendTimer backendTimer; + + public ParameterDefaultDataset(BackendTimer timer) { + this(timer, ParameterDefaultDataset::mtq1EnabledConversionFunction); + } + public ParameterDefaultDataset(BackendTimer timer, ConversionFunction mtq1EnabledSpecificConversionFunction) { + super(timer); + + // the Mtq1Enabled conversion function requires access to the timer + backendTimer = timer; + + // build ParameterDefinition objects + + // ParameterDefinition + // - identity: ("fr.cnes.mission.sat1", "ATT_BC_MTQ1VOLTAGE", version=1) + // - description: "" + // - rawType: DOUBLE + // - rawUnit: "V" + // - convertedType: null + // - convertedUnit: null + // Default Report Configuration + // - reportingEnabled: true + // - reportInterval: 300s (minimum sampling interval=60s) + // ParameterDefinition + // - identity: ("fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1) + // - description: "" + // - rawType: UINTEGER + // - rawUnit: null + // - convertedType: String + // - convertedUnit: null + // Default Report Configuration + // - reportingEnabled: false + // - reportInterval: 300s (minimum sampling interval=300s) + DefaultReportConfiguration config = new DefaultReportConfiguration(true, 300*1000, 60*1000); + sat1Mtq1VoltagePdId = + addParameter( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1)), + new String("absolute time in seconds"), + AttributeType.DOUBLE, + new String("V"), + null, null, + config, + ParameterDataset::noConversionFunction, + false); + config = new DefaultReportConfiguration(false, 300*1000, 300*1000); + sat1Mtq1EnabledPdId = + addParameter( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1ENABLED, + new UInteger(1)), + new String(""), + AttributeType.UINTEGER, + null, + AttributeType.STRING, + null, + config, + mtq1EnabledSpecificConversionFunction, + false); + + // register all values + addValues(); + } + + void addValues() { + // at this time, the timer must have been initialized to the time origin + long timeOrigin = timer.currentTimeMillis(); + + // paramRef.domain paramRef.key timestamp samplingTime rawValue + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:00:10 0:00:00 12.00 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1ENABLED" 0:00:10 0:00:00 1 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:01:10 0:01:00 12.01 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:02:10 0:02:00 12.02 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:03:10 0:03:00 12.03 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:04:10 0:04:00 12.04 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:05:10 0:05:00 12.05 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:10:10 0:06:00 12.06 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:10:10 0:07:00 12.07 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:10:10 0:08:00 12.08 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:11:10 0:09:00 12.09 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:11:10 0:10:00 12.10 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:11:10 0:11:00 12.11 + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+10*1000, timeOrigin, new Union(new Double(12.00))); + addParameterValue(sat1Mtq1EnabledPdId, timeOrigin+10*1000, timeOrigin, new UInteger(1)); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((1*60)+10)*1000, timeOrigin+1*60*1000, new Union(new Double(12.01))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((2*60)+10)*1000, timeOrigin+2*60*1000, new Union(new Double(12.02))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((3*60)+10)*1000, timeOrigin+3*60*1000, new Union(new Double(12.03))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((4*60)+10)*1000, timeOrigin+4*60*1000, new Union(new Double(12.04))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((5*60)+10)*1000, timeOrigin+5*60*1000, new Union(new Double(12.05))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((10*60)+10)*1000, timeOrigin+6*60*1000, new Union(new Double(12.06))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((10*60)+10)*1000, timeOrigin+7*60*1000, new Union(new Double(12.07))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((10*60)+10)*1000, timeOrigin+8*60*1000, new Union(new Double(12.08))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((11*60)+10)*1000, timeOrigin+9*60*1000, new Union(new Double(12.09))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((11*60)+10)*1000, timeOrigin+10*60*1000, new Union(new Double(12.10))); + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+((11*60)+10)*1000, timeOrigin+11*60*1000, new Union(new Double(12.11))); + } + + /** + * Specific conversion function for the parameter ATT-BC-MTQ1ENABLED. + * - 0 → "DISABLED" + * - 1 → "ENABLED" + * - >1&<8 → valid value but fails conversion + * - >=8 → "UNKNOWN" (the raw value is considered invalid) + * Any value older that 10mn becomes EXPIRED + * + * @param parameterID + * @param rawValue + * @return + */ + public static ParameterValueData mtq1EnabledConversionFunction(int parameterID, ParameterRawValue rawValue) { + if (rawValue == null || rawValue.rawValue == null) + return new ParameterValueData(ValidityState.INVALID_RAW, null, null); + if (!(rawValue.rawValue instanceof UInteger)) + return new ParameterValueData(ValidityState.INVALID_CONVERSION, rawValue.rawValue, null); + long rawInt = ((UInteger) rawValue.rawValue).getValue(); + if (rawInt == 0) + return new ParameterValueData( + ValidityState.VALID, + rawValue.rawValue, Constant.AT_STRING_DISABLED); + if (rawInt == 1) + return new ParameterValueData( + ValidityState.VALID, + rawValue.rawValue, Constant.AT_STRING_ENABLED); + return new ParameterValueData(ValidityState.INVALID, rawValue.rawValue, Constant.AT_STRING_UNKNOWN); + } +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterErrorDataset.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterErrorDataset.java new file mode 100755 index 000000000..cf481a8b6 --- /dev/null +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/ParameterErrorDataset.java @@ -0,0 +1,169 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2024 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed.backends; + +import org.ccsds.moims.mo.mal.structures.AttributeType; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mc.ActionDataset; +import org.ccsds.moims.mo.mc.ParameterDataset; +import org.ccsds.moims.mo.mc.backends.BackendTimer; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinition; +import org.ccsds.moims.mo.mc.structures.ArgumentDefinitionList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.ccsds.mo.mc.testbed.Constant; + +/** + * ParameterErrorDataset implements the dataset #PA-9. + */ +public class ParameterErrorDataset extends ParameterDataset { + + public static final ObjectRef sat1Mtq1VoltageRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ParameterDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1VOLTAGE, + new UInteger(1)); + public final int sat1Mtq1VoltagePdId; + public static final ObjectRef sat2Mtq1VoltageRef = + new ObjectRef<>( + Constant.DOMAIN_SAT2, + ParameterDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1VOLTAGE, + new UInteger(1)); + public final int sat2Mtq1VoltagePdId; + public static final ObjectRef sat1Mtq1EnabledRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ParameterDefinition.TYPE_ID.getTypeId(), + Constant.ID_MTQ1ENABLED, + new UInteger(1)); + public final int sat1Mtq1EnabledPdId; + + public ParameterErrorDataset(BackendTimer timer) { + super(timer); + + // the Mtq1Enabled conversion function requires access to the timer + ParameterDefaultDataset.backendTimer = timer; + + // build ParameterDefinition objects + + // ParameterDefinition + // - identity: ("fr.cnes.mission.sat1", "ATT_BC_MTQ1VOLTAGE", version=1) + // - description: "" + // - rawType: DOUBLE + // - rawUnit: "V" + // - convertedType: null + // - convertedUnit: null + // Default Report Configuration + // - reportingEnabled: true + // - reportInterval: 300s (minimum sampling interval=60s) + // ParameterDefinition + // - identity: ("fr.cnes.mission.sat2", "ATT_BC_MTQ1VOLTAGE", version=1) + // - description: "" + // - rawType: DOUBLE + // - rawUnit: "V" + // - convertedType: null + // - convertedUnit: null + // Default Report Configuration + // - reportingEnabled: false + // - reportInterval: 300s (minimum sampling interval=300s) + // ParameterDefinition + // - identity: ("fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1) + // - description: "" + // - rawType: UINTEGER + // - rawUnit: null + // - convertedType: String + // - convertedUnit: null + // Default Report Configuration + // - reportingEnabled: false + // - reportInterval: 300s (minimum sampling interval=300s) + sat1Mtq1VoltagePdId = + addParameter( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1)), + new String("absolute time in seconds"), + AttributeType.DOUBLE, + new String("V"), + null, null, + new DefaultReportConfiguration(true, 300*1000, 60*1000), + ParameterDataset::noConversionFunction, + false); + sat2Mtq1VoltagePdId = + addParameter( + new ObjectIdentity( + Constant.DOMAIN_SAT2, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1)), + new String("absolute time in seconds"), + AttributeType.DOUBLE, + new String("V"), + null, null, + new DefaultReportConfiguration(false, 300*1000, 300*1000), + ParameterDataset::noConversionFunction, + true); + sat1Mtq1EnabledPdId = + addParameter( + new ObjectIdentity( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1ENABLED, + new UInteger(1)), + new String(""), + AttributeType.UINTEGER, + null, + AttributeType.STRING, null, + new DefaultReportConfiguration(false, 300*1000, 300*1000), + ParameterDefaultDataset::mtq1EnabledConversionFunction, + false); + + // register all values + addValues(); + } + + void addValues() { + // at this time, the timer must have been initialized to the time origin + long timeOrigin = timer.currentTimeMillis(); + + // paramRef.domain paramRef.key timestamp samplingTime rawValue + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1VOLTAGE" 0:00:10 0:00:00 12.00 + // "fr.cnes.mission.sat2" "ATT_BC_MTQ1VOLTAGE" 0:00:10 0:00:00 22.00 + // "fr.cnes.mission.sat1" "ATT_BC_MTQ1ENABLED" 0:00:10 0:00:00 1 + addParameterValue(sat1Mtq1VoltagePdId, timeOrigin+10*1000, timeOrigin, new Union(new Double(12.00))); + addParameterValue(sat2Mtq1VoltagePdId, timeOrigin+10*1000, timeOrigin, new Union(new Double(22.00))); + addParameterValue(sat1Mtq1EnabledPdId, timeOrigin+10*1000, timeOrigin, new UInteger(1)); + } +} diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/package-info.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/package-info.java index bdce9fc59..3581dc59b 100644 --- a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/package-info.java +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/backends/package-info.java @@ -1,4 +1,7 @@ /** - * Package containing the MC testbed backends. These will be used by the testing classes. + * Package containing the M&C testbed backends. These will be used by the testing classes. + * + * It also includes the implementation of a BackendTimer, which provides for a simulated time in the tests. + * This BackendTimer is notably used by the tests of the Parameter and Aggregation services. */ package org.ccsds.mo.mc.testbed.backends; diff --git a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/package-info.java b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/package-info.java index c0dfa2042..426dc2669 100644 --- a/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/package-info.java +++ b/testbeds/testbed-mc/src/main/java/org/ccsds/mo/mc/testbed/package-info.java @@ -1,4 +1,4 @@ /** - * Package containing utility classes for the MC testbed. + * Package containing utility classes for the M&C testbed. */ package org.ccsds.mo.mc.testbed; diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_1_Basic_Execution_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_1_Basic_Execution_Test.java new file mode 100755 index 000000000..f032fc1f7 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_1_Basic_Execution_Test.java @@ -0,0 +1,103 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.backends.ActionBasicDataset; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * AC_1_Basic_Execution_Test implements the test scenario #AC-1. + */ +public class AC_1_Basic_Execution_Test extends ActionTestClient { + + static ActionListener actionListener = new ActionListener(); + + private static final ActionBasicDataset backend = new ActionBasicDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AC_1_Basic_Execution_Test.class.getName())); + setUp.setUp(backend, null, null, null, null, + true, false, false, false, false); + actionConsumerStub = setUp.getActionConsumer(); + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AC_1_Basic_Execution_Test.class.getName() + " tearDownClass()"); + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * Simplest nominal case for an action execution + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=111 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="SAT_TC_CHGTABSVAL" + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=false + // - stageCompletedRequired=false + // - argumentsValues={ {value=10000} } + // check ACK message + Long requestId = new Long(111); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionBasicDataset.sat1ChgTAbsValRef, + null, + false, + false, + false, + CHGTABSVAL_DFLT_ARGS), + actionListener, + startTime + TIMEOUT); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_2_Basic_Monitor_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_2_Basic_Monitor_Test.java new file mode 100644 index 000000000..87eb14dd6 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_2_Basic_Monitor_Test.java @@ -0,0 +1,168 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.ActionListener.MonitorExecutionUpdate; +import org.ccsds.mo.mc.testbed.ParameterListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.ActionBasicDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Element; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.action.consumer.ActionAdapter; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ActionCompleteEvent; +import org.ccsds.moims.mo.mc.structures.ActionDefinition; +import org.ccsds.moims.mo.mc.structures.ActionEvent; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; +import org.ccsds.moims.mo.mc.structures.ActionStartEvent; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * AC_1_Basic_Execution_Test implements the test scenario #AC-2. + */ +public class AC_2_Basic_Monitor_Test extends ActionTestClient { + + static ActionListener actionListener = new ActionListener(); + static Identifier subscriptionId = new Identifier("21"); + + private static final ActionBasicDataset backend = new ActionBasicDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AC_2_Basic_Monitor_Test.class.getName())); + setUp.setUp(backend, null, null, null, null, + true, false, false, false, false); + actionConsumerStub = setUp.getActionConsumer(); + + // call monitorExecution.register with subscription + // subscription= + // - subscriptionId=21 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + execAndCheckMonitorExecutionRegister( + new Subscription( + subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + actionListener, + System.currentTimeMillis() + TIMEOUT); + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AC_2_Basic_Monitor_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + actionListener.reset(); + execAndCheckMonitorExecutionDeregister( + subscriptions, + actionListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * Simplest nominal case for an action execution with monitoring + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=211 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="SAT_TC_CHGTABSVAL" + // - source=null + // - stageStartedRequired=true + // - stageProgressRequired=true + // - stageCompletedRequired=true + // - argumentsValues={ {value=10000} } + // check ACK message + Long requestId = new Long(211); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionBasicDataset.sat1ChgTAbsValRef, + null, + true, + true, + true, + CHGTABSVAL_DFLT_ARGS), + actionListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription: + // ActionStartEvent: success=true + // ActionCompleteEvent: success=true + MonitorExecutionUpdate[] targetUpdates = new MonitorExecutionUpdate[2]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_CHGTABSVAL, + ActionCategory.DEFAULT, + new ActionStartEvent(true)); + targetUpdates[1] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_CHGTABSVAL, + ActionCategory.DEFAULT, + new ActionCompleteEvent(true)); + waitAndCheckForUpdates(actionListener, startTime + TIMEOUT, targetUpdates); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_3_Extended_Execution_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_3_Extended_Execution_Test.java new file mode 100755 index 000000000..be8430dd3 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_3_Extended_Execution_Test.java @@ -0,0 +1,273 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.ActionListener.MonitorExecutionUpdate; +import org.ccsds.mo.mc.testbed.backends.ActionBasicDataset; +import org.ccsds.mo.mc.testbed.backends.ActionDefaultDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Element; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.ULong; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.action.consumer.ActionAdapter; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ActionCompleteEvent; +import org.ccsds.moims.mo.mc.structures.ActionDefinition; +import org.ccsds.moims.mo.mc.structures.ActionEvent; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; +import org.ccsds.moims.mo.mc.structures.ActionStartEvent; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * AC_3_Extended_Execution_Test implements the test scenario #AC-3. + */ +public class AC_3_Extended_Execution_Test extends ActionTestClient { + + static ActionListener actionListener = new ActionListener(); + static Identifier subscriptionId = new Identifier("31"); + + private static final ActionDefaultDataset backend = new ActionDefaultDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AC_3_Extended_Execution_Test.class.getName())); + setUp.setUp(backend, null, null, null, null, + true, false, false, false, false); + actionConsumerStub = setUp.getActionConsumer(); + + // call monitorExecution.register with subscription + // subscription= + // - subscriptionId=31 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + execAndCheckMonitorExecutionRegister( + new Subscription( + subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + actionListener, + System.currentTimeMillis() + TIMEOUT); + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AC_3_Extended_Execution_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + actionListener.reset(); + execAndCheckMonitorExecutionDeregister( + subscriptions, + actionListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * Test the nominal case for an action execution. + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=311 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="SAT_TC_CHGTABSVAL" + // - actionRef version=1 + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=false + // - stageCompletedRequired=false + // - argumentsValues={ {value=10000} } + // check ACK message + Long requestId = new Long(311); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1ChgTAbsValRef, + null, + false, + false, + false, + CHGTABSVAL_DFLT_ARGS), + actionListener, + startTime + TIMEOUT); + + // additional statements for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * Requires previous execution of Test Case 1. + * Test the nominal case with monitoring + */ + @Test + public void testCase_02() { + // additional statements for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=321 + // - actionRef domain="fr.cnes.mission.sat2" + // - actionRef key="SAT_TC_CHGTABSVAL" + // - actionRef version=1 + // - source=null + // - stageStartedRequired=true + // - stageProgressRequired=true + // - stageCompletedRequired=true + // - argumentsValues={ {value=10000} } + // check ACK message + Long requestId = new Long(321); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat2ChgTAbsValRef, + null, + true, + true, + true, + CHGTABSVAL_DFLT_ARGS), + actionListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription: + // ActionStartEvent: success=true + // ActionCompleteEvent: success=true + MonitorExecutionUpdate[] targetUpdates = new MonitorExecutionUpdate[2]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT2, + requestId, + Constant.ID_CHGTABSVAL, + ActionCategory.DEFAULT, + new ActionStartEvent(true)); + targetUpdates[1] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT2, + requestId, + Constant.ID_CHGTABSVAL, + ActionCategory.DEFAULT, + new ActionCompleteEvent(true)); + waitAndCheckForUpdates(actionListener, startTime + TIMEOUT, targetUpdates); + + // additional statements for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * Requires previous execution of Test Case 2. + * Test the unfilled version for actionRef. + */ + @Test + public void testCase_03() { + // additional statements for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=331 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="MIS_TC_DEFATTITUDE" + // - actionRef version=0 + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=false + // - stageCompletedRequired=false + // - argumentsValues={ {value=2.1E9}, {value=6.0E1}, {value="ok"}, {value=0}, {value=1.3E0}, {value=null}, {value=null} } + // check ACK message + Long requestId = new Long(331); + ObjectRef actionRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + ActionDefinition.TYPE_ID.getTypeId(), + Constant.ID_DEFATTITUDE, + new UInteger(0)); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + actionRef, + null, + false, + false, + false, + DEFATTITUDE_DFLT_ARGS), + actionListener, + startTime + TIMEOUT); + + // additional statements for dependent tests + TestDependency.after(); + } +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_4_Extended_Monitoring_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_4_Extended_Monitoring_Test.java new file mode 100755 index 000000000..cbe2da9f6 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_4_Extended_Monitoring_Test.java @@ -0,0 +1,499 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.ActionListener.MonitorExecutionUpdate; +import org.ccsds.mo.mc.testbed.backends.ActionBasicDataset; +import org.ccsds.mo.mc.testbed.backends.ActionDefaultDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Element; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.ULong; +import org.ccsds.moims.mo.mal.structures.UOctet; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.action.consumer.ActionAdapter; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ActionCompleteEvent; +import org.ccsds.moims.mo.mc.structures.ActionDefinition; +import org.ccsds.moims.mo.mc.structures.ActionEvent; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; +import org.ccsds.moims.mo.mc.structures.ActionInProgressEvent; +import org.ccsds.moims.mo.mc.structures.ActionStartEvent; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * + */ +public class AC_4_Extended_Monitoring_Test extends ActionTestClient { + + static ActionListener actionListener = new ActionListener(); + static Identifier subscriptionId = new Identifier("41"); + + private static final ActionDefaultDataset backend = new ActionDefaultDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AC_4_Extended_Monitoring_Test.class.getName())); + setUp.setUp(backend, null, null, null, null, + true, false, false, false, false); + actionConsumerStub = setUp.getActionConsumer(); + + // call monitorExecution.register with subscription + // subscription= + // - subscriptionId=41 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + execAndCheckMonitorExecutionRegister( + new Subscription( + subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + actionListener, + System.currentTimeMillis() + TIMEOUT); + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AC_4_Extended_Monitoring_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + actionListener.reset(); + execAndCheckMonitorExecutionDeregister( + subscriptions, + actionListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * Test a complete nominal case for an action execution monitoring. + */ + @Test + public void testCase_01() { + // additional statements for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=411 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="MIS_TC_DEFATTITUDE" + // - source=null + // - stageStartedRequired=true + // - stageProgressRequired=true + // - stageCompletedRequired=true + // - argumentsValues={ {value=2.1E9}, {value=6.0E1}, {value="ok"}, {value=0}, {value=1.3E0}, {value=null}, {value=null} } + // check ACK message + Long requestId = new Long(411); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + true, + true, + true, + DEFATTITUDE_DFLT_ARGS), + actionListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={requestId=411, actionKey="MIS_TC_DEFATTITUDE", actionCategory=DEFAULT}: + // - ActionStartEvent: success=true + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=1 + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=2 + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=3 + // - ActionCompleteEvent: success=true + MonitorExecutionUpdate[] targetUpdates = new MonitorExecutionUpdate[5]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionStartEvent(true)); + targetUpdates[1] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(1))); + targetUpdates[2] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(2))); + targetUpdates[3] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(3))); + targetUpdates[4] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionCompleteEvent(true)); + waitAndCheckForUpdates(actionListener, startTime + TIMEOUT, targetUpdates); + + // additional statements for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * Requires previous execution of Test Case 1. + * Test partial sending of ActionEvents + */ + @Test + public void testCase_02() { + // additional statements for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=421 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="MIS_TC_DEFATTITUDE" + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=true + // - stageCompletedRequired=true + // - argumentsValues={ {value=2.1E9}, {value=6.0E1}, {value="ok"}, {value=0}, {value=1.3E0}, {value=null}, {value=null} } + // check ACK message + Long requestId = new Long(421); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + false, + true, + true, + DEFATTITUDE_DFLT_ARGS), + actionListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription: + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=1 + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=2 + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=3 + // - ActionCompleteEvent: success=true + MonitorExecutionUpdate[] targetUpdates = new MonitorExecutionUpdate[4]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(1))); + targetUpdates[1] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(2))); + targetUpdates[2] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(3))); + targetUpdates[3] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionCompleteEvent(true)); + waitAndCheckForUpdates(actionListener, startTime + TIMEOUT, targetUpdates); + + // additional statements for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * Requires previous execution of Test Case 2. + * Test partial sending of ActionEvents + */ + @Test + public void testCase_03() { + // additional statements for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=411 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="MIS_TC_DEFATTITUDE" + // - source=null + // - stageStartedRequired=true + // - stageProgressRequired=false + // - stageCompletedRequired=true + // - argumentsValues={ {value=2.1E9}, {value=6.0E1}, {value="ok"}, {value=0}, {value=1.3E0}, {value=null}, {value=null} } + // check ACK message + Long requestId = new Long(431); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + true, + false, + true, + DEFATTITUDE_DFLT_ARGS), + actionListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription: + // - ActionStartEvent: success=true + // - ActionCompleteEvent: success=true + MonitorExecutionUpdate[] targetUpdates = new MonitorExecutionUpdate[2]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionStartEvent(true)); + targetUpdates[1] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionCompleteEvent(true)); + waitAndCheckForUpdates(actionListener, startTime + TIMEOUT, targetUpdates); + + // additional statements for dependent tests + TestDependency.after(); + } + + /** + * Test Case 4. + * Requires previous execution of Test Case 3. + * Test partial sending of ActionEvents + */ + @Test + public void testCase_04() { + // additional statements for dependent tests + TestDependency.before(3, this, "testCase_03", 4); + + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=441 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="MIS_TC_DEFATTITUDE" + // - source=null + // - stageStartedRequired=true + // - stageProgressRequired=true + // - stageCompletedRequired=false + // - argumentsValues={ {value=2.1E9}, {value=6.0E1}, {value="ok"}, {value=0}, {value=1.3E0}, {value=null}, {value=null} } + // check ACK message + Long requestId = new Long(441); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + true, + true, + false, + DEFATTITUDE_DFLT_ARGS), + actionListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription: + // - ActionStartEvent: success=true + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=1 + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=2 + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=3 + MonitorExecutionUpdate[] targetUpdates = new MonitorExecutionUpdate[4]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionStartEvent(true)); + targetUpdates[1] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(1))); + targetUpdates[2] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(2))); + targetUpdates[3] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(3))); + waitAndCheckForUpdates(actionListener, startTime + TIMEOUT, targetUpdates); + + // additional statements for dependent tests + TestDependency.after(); + } + + /** + * Test Case 5. + * Requires previous execution of Test Case 4. + * Test interrupted sequence of ActionInProgressEvent messages + */ + @Test + public void testCase_05() { + // additional statements for dependent tests + TestDependency.before(4, this, "testCase_04", 5); + + System.out.println("Running: testCase_05()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=451 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="MIS_TC_DEFATTITUDE" + // - source=null + // - stageStartedRequired=true + // - stageProgressRequired=true + // - stageCompletedRequired=true + // - argumentsValues={ {value=2.1E9}, {value=6.0E1}, {value="fail-2"}, {value=0}, {value=1.3E0}, {value=null}, {value=null} } + // check ACK message + Long requestId = new Long(451); + NullableAttributeList argumentValues = (NullableAttributeList) DEFATTITUDE_DFLT_ARGS.clone(); + argumentValues.set(2, NA_STRING_FAIL2); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + true, + true, + true, + argumentValues), + actionListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription: + // - ActionStartEvent: success=true + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=1 + // - ActionInProgressEvent: success=false, stageCount=3, executionStage=2 + // - ActionCompleteEvent: success=false + MonitorExecutionUpdate[] targetUpdates = new MonitorExecutionUpdate[4]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionStartEvent(true)); + targetUpdates[1] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(1))); + targetUpdates[2] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(false, new UInteger(3), new UInteger(2))); + targetUpdates[3] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionCompleteEvent(false)); + waitAndCheckForUpdates(actionListener, startTime + TIMEOUT, targetUpdates); + + // additional statements for dependent tests + TestDependency.after(); + } +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_5_Special_Monitoring_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_5_Special_Monitoring_Test.java new file mode 100755 index 000000000..9eaec687b --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_5_Special_Monitoring_Test.java @@ -0,0 +1,231 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.ActionListener.MonitorExecutionUpdate; +import org.ccsds.mo.mc.testbed.backends.ActionBasicDataset; +import org.ccsds.mo.mc.testbed.backends.ActionDefaultDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Element; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.ULong; +import org.ccsds.moims.mo.mal.structures.UOctet; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.action.consumer.ActionAdapter; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ActionCompleteEvent; +import org.ccsds.moims.mo.mc.structures.ActionDefinition; +import org.ccsds.moims.mo.mc.structures.ActionEvent; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; +import org.ccsds.moims.mo.mc.structures.ActionInProgressEvent; +import org.ccsds.moims.mo.mc.structures.ActionStartEvent; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * + */ +public class AC_5_Special_Monitoring_Test extends ActionTestClient { + + static ActionListener actionListener1 = new ActionListener(); + static ActionListener actionListener2 = new ActionListener(); + static Identifier subscription1Id = new Identifier("51"); + static Identifier subscription2Id = new Identifier("52"); + + private static final ActionDefaultDataset backend = new ActionDefaultDataset(); + + private static int testStep = 0; + private static boolean testStatus = true; + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AC_5_Special_Monitoring_Test.class.getName())); + setUp.setUp(backend, null, null, null, null, + true, false, false, false, false); + actionConsumerStub = setUp.getActionConsumer(); + + // call monitorExecution.register with subscription-1 + // subscription-1= + // - subscriptionId=51 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + execAndCheckMonitorExecutionRegister( + new Subscription( + subscription1Id, + Constant.DOMAIN_WILDCARD, + null, null), + actionListener1, + System.currentTimeMillis() + TIMEOUT); + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AC_5_Special_Monitoring_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscription1Id); + subscriptions.add(subscription2Id); + actionListener1.reset(); + execAndCheckMonitorExecutionDeregister( + subscriptions, + actionListener1, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * Test a complete nominal case for an action execution monitoring. + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + actionListener1.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=511 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="MIS_TC_DEFATTITUDE" + // - source=null + // - stageStartedRequired=true + // - stageProgressRequired=true + // - stageCompletedRequired=true + // - argumentsValues={ {value=2.1E9}, {value=6.0E1}, {value="wait"}, {value=0}, {value=1.3E0}, {value=null}, {value=null} } + // check ACK message + Long requestId = new Long(511); + NullableAttributeList argumentValues = (NullableAttributeList) DEFATTITUDE_DFLT_ARGS.clone(); + argumentValues.set(2, NA_STRING_WAIT); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + true, + true, + true, + argumentValues), + actionListener1, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription-1: + // - ActionStartEvent: success=true + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=1 + MonitorExecutionUpdate[] targetUpdates = new MonitorExecutionUpdate[2]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionStartEvent(true)); + targetUpdates[1] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(1))); + waitAndCheckForUpdates(actionListener1, startTime + TIMEOUT, targetUpdates); + + // call monitorExecution.register with subscription-2 + // subscription-2= + // - subscriptionId=52 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + actionListener2.reset(); + execAndCheckMonitorExecutionRegister( + new Subscription( + subscription2Id, + Constant.DOMAIN_WILDCARD, + null, null), + actionListener2, + startTime + TIMEOUT); + + actionListener1.reset(); + actionListener2.reset(); + // call backend:resumeAction with requestId=511 + System.out.println("call backend:resumeAction"); + backend.resumeAction(requestId); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription-1 and subscription-2: + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=2 + // - ActionInProgressEvent: success=true, stageCount=3, executionStage=3 + // - ActionCompleteEvent: success=true + targetUpdates = new MonitorExecutionUpdate[3]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(2))); + targetUpdates[1] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionInProgressEvent(true, new UInteger(3), new UInteger(3))); + targetUpdates[2] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionCompleteEvent(true)); + waitAndCheckForUpdates(actionListener1, startTime + TIMEOUT, targetUpdates); + waitAndCheckForUpdates(actionListener2, startTime + TIMEOUT, targetUpdates); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_9_Execution_Error_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_9_Execution_Error_Test.java new file mode 100755 index 000000000..6fbe9b1a7 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AC_9_Execution_Error_Test.java @@ -0,0 +1,445 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.ActionListener.MonitorExecutionUpdate; +import org.ccsds.mo.mc.testbed.backends.ActionBasicDataset; +import org.ccsds.mo.mc.testbed.backends.ActionDefaultDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALHelper; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Element; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.MCHelper; +import org.ccsds.moims.mo.mc.action.consumer.ActionAdapter; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ActionCompleteEvent; +import org.ccsds.moims.mo.mc.structures.ActionDefinition; +import org.ccsds.moims.mo.mc.structures.ActionEvent; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; +import org.ccsds.moims.mo.mc.structures.ActionInProgressEvent; +import org.ccsds.moims.mo.mc.structures.ActionStartEvent; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * + */ +public class AC_9_Execution_Error_Test extends ActionTestClient { + + static ActionListener actionListener = new ActionListener(); + static Identifier subscriptionId = new Identifier("91"); + + private static final ActionDefaultDataset backend = new ActionDefaultDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AC_9_Execution_Error_Test.class.getName())); + setUp.setUp(backend, null, null, null, null, + true, false, false, false, false); + actionConsumerStub = setUp.getActionConsumer(); + + // call monitorExecution.register with subscription + // subscription= + // - subscriptionId=91 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + execAndCheckMonitorExecutionRegister( + new Subscription( + subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + actionListener, + System.currentTimeMillis() + TIMEOUT); + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AC_9_Execution_Error_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + actionListener.reset(); + execAndCheckMonitorExecutionDeregister( + subscriptions, + actionListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * execute an action which is not declared + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=911 + // - actionRef domain="fr.cnes.mission.unknown" + // - actionRef key="SAT_TC_CHGTABSVAL" + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=false + // - stageCompletedRequired=false + // - argumentsValues={ {value=10000} } + // check ERROR message with code Unknown + Long requestId = new Long(911); + System.out.println("call execute with executionRequest"); + execAndCheckErrorExecute( + new ActionExecutionRequest( + requestId, + new ObjectRef<>( + Constant.DOMAIN_UNKNOWN, + ActionDefinition.TYPE_ID.getTypeId(), + Constant.ID_CHGTABSVAL, + new UInteger(0)), + null, + false, + false, + false, + CHGTABSVAL_DFLT_ARGS), + actionListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + null); + } + + /** + * Test Case 2. + * reuse the same id in two executionRequests + */ + @Test + public void testCase_02() { + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=921 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="SAT_TC_CHGTABSVAL" + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=false + // - stageCompletedRequired=false + // - argumentsValues={ {value=10000} } + Long requestId = new Long(921); + ActionExecutionRequest request = + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1ChgTAbsValRef, + null, + false, + false, + false, + CHGTABSVAL_DFLT_ARGS); + System.out.println("call execute with executionRequest"); + execAndCheckExecute( + request, + actionListener, + startTime + TIMEOUT); + + actionListener.reset(); + // call execute again with same executionRequest + // check ERROR message with code Duplicate + execAndCheckErrorExecute( + request, + actionListener, + startTime + TIMEOUT, + MCHelper.DUPLICATE_ERROR_NUMBER, + null); + } + + /** + * Test Case 3. + * provide an incorrect null value as arguments list of the executionRequest + */ + @Test + public void testCase_03() { + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=931 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="SAT_TC_CHGTABSVAL" + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=false + // - stageCompletedRequired=false + // - argumentsValues=null + // check ERROR message with code Invalid + // check the extraInfo field as a singleton list holding element 0 + Long requestId = new Long(931); + System.out.println("call execute with executionRequest"); + execAndCheckErrorExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1ChgTAbsValRef, + null, + false, + false, + false, + null), + actionListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + new UIntegerList(new ArrayList<>(Arrays.asList( + new UInteger(0))))); + } + + /** + * Test Case 4. + * provide an incorrect typed value as argument of the executionRequest + */ + @Test + public void testCase_04() { + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=941 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="SAT_TC_CHGTABSVAL" + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=false + // - stageCompletedRequired=false + // - argumentsValues={ {value="incorrect type"} } + // check ERROR message with code Invalid + // check the extraInfo field as a singleton list holding element 0 + Long requestId = new Long(941); + System.out.println("call execute with executionRequest"); + execAndCheckErrorExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1ChgTAbsValRef, + null, + false, + false, + false, + new NullableAttributeList(new ArrayList<> (Arrays.asList( + new NullableAttribute(new Union(new String("incorrect type"))))))), + actionListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + new UIntegerList(new ArrayList<>(Arrays.asList( + new UInteger(0))))); + } + + /** + * Test Case 5. + * trigger the provider specific check to fail + */ + @Test + public void testCase_05() { + System.out.println("Running: testCase_05()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest + // executionRequest= + // - requestId=951 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="MIS_TC_DEFATTITUDE" + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=false + // - stageCompletedRequired=false + // - argumentsValues={ {value=2.1E9}, {value=6.0E1}, {value="error Rejected"}, {value=0}, {value=1.3E0}, {value=null}, {value=null} } + // check ERROR message with code Rejected + Long requestId = new Long(951); + NullableAttributeList argumentValues = (NullableAttributeList) DEFATTITUDE_DFLT_ARGS.clone(); + argumentValues.set(2, NA_STRING_ERROR_REJECTED); + System.out.println("call execute with executionRequest"); + execAndCheckErrorExecute( + new ActionExecutionRequest( + requestId, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + false, + false, + false, + argumentValues), + actionListener, + startTime + TIMEOUT, + MCHelper.REJECTED_ERROR_NUMBER, + null); + // check the extraInfo field as a String if not null + if (actionListener.error.getExtraInformation() != null) { + // the Java mapping types the extraInformation field as a Java Object + // it is unclear how the Java mapping types the returned String + // we test the Java String and a MAL Union holding a String + Object extraInfo = actionListener.error.getExtraInformation(); + if (!(extraInfo instanceof String || + extraInfo instanceof Union && ((Union) extraInfo).isStringAttribute())) + unitTestFail("Wrong type for extraInfo field, expected String, was " + + extraInfo.getClass().getName()); + } + } + + /** + * Test Case 6. + * check action execution depends on provider specific check + */ + @Test + public void testCase_06() { + System.out.println("Running: testCase_06()"); + long startTime = System.currentTimeMillis(); + + actionListener.reset(); + // call execute with executionRequest-1 + // executionRequest-1= + // - requestId=961 + // - actionRef domain="fr.cnes.mission.sat1" + // - actionRef key="MIS_TC_DEFATTITUDE" + // - actionRef version=0 + // - source=null + // - stageStartedRequired=false + // - stageProgressRequired=false + // - stageCompletedRequired=true + // - argumentsValues={ {value=2.1E9}, {value=6.0E1}, {value="skip"}, {value=0}, {value=1.3E0}, {value=null}, {value=null} } + // check ACK message + Long requestId1 = new Long(961); + NullableAttributeList argumentValues = (NullableAttributeList) DEFATTITUDE_DFLT_ARGS.clone(); + argumentValues.set(2, NA_STRING_SKIP); + System.out.println("call execute with executionRequest1"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId1, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + false, + false, + true, + argumentValues), + actionListener, + startTime + TIMEOUT); + + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription + // - ActionCompleteEvent: success=true + MonitorExecutionUpdate[] targetUpdates = new MonitorExecutionUpdate[1]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId1, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionCompleteEvent(true)); + waitAndCheckForUpdates(actionListener, startTime + TIMEOUT, targetUpdates); + + // call execute with executionRequest-2 + // executionRequest-2= same as executionRequest-1 but + // -requestId=962 + // check ERROR message with code Rejected + actionListener.reset(); + Long requestId2 = new Long(962); + System.out.println("call execute with executionRequest2"); + execAndCheckErrorExecute( + new ActionExecutionRequest( + requestId2, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + false, + false, + true, + DEFATTITUDE_DFLT_ARGS), + actionListener, + startTime + TIMEOUT, + MCHelper.REJECTED_ERROR_NUMBER, + new Union(Constant.STR_SKIPPED)); + + // call execute with executionRequest-3 + // executionRequest-3= same as executionRequest-1 but + // -requestId=963 + // -- {value="ok"} + // check ACK message + actionListener.reset(); + Long requestId3 = new Long(963); + argumentValues = (NullableAttributeList) DEFATTITUDE_DFLT_ARGS.clone(); + argumentValues.set(2, NA_STRING_OK); + System.out.println("call execute with executionRequest3"); + execAndCheckExecute( + new ActionExecutionRequest( + requestId3, + ActionDefaultDataset.sat1DefAttitude2Ref, + null, + false, + false, + true, + argumentValues), + actionListener, + startTime + TIMEOUT); + + // Wait for all updates or TIMOUT + // check reception of ActionEvents from subscription + // - ActionCompleteEvent: success=true + targetUpdates = new MonitorExecutionUpdate[1]; + targetUpdates[0] = new MonitorExecutionUpdate( + Constant.DOMAIN_SAT1, + requestId3, + Constant.ID_DEFATTITUDE, + ActionCategory.DEFAULT, + new ActionCompleteEvent(true)); + waitAndCheckForUpdates(actionListener, startTime + TIMEOUT, targetUpdates); + + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_1_Basic_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_1_Basic_Test.java new file mode 100755 index 000000000..fbaeeb304 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_1_Basic_Test.java @@ -0,0 +1,223 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.AggregationListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.AggregationBasicDataset; +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterBasicDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.parameter.consumer.ParameterAdapter; +import org.ccsds.moims.mo.mc.parameter.provider.ParameterInheritanceSkeleton; +import org.ccsds.moims.mo.mc.structures.AggregationValue; +import org.ccsds.moims.mo.mc.structures.AggregationValueList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueDataList; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * AG_1_Basic_Test implements the test scenario #AG-1. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AG_1_Basic_Test extends AggregationTestClient { + + static AggregationListener aggregationListener = new AggregationListener(); + static Identifier subscriptionId; + + // timeOrigin=1/1/2025 01:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 1, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterBasicDataset parameterBackend = new ParameterBasicDataset(timer); + private static AggregationBasicDataset backend; + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AG_1_Basic_Test.class.getName())); + setUp.setUp(null, null, null, null, parameterBackend, + false, false, false, false, true); + + if (setUp.getParameterProvider() == null) { + unitTestFail("cannot find the Parameter provider"); + } + SingleConnectionDetails parameterDetails = + setUp.getParameterProvider().getConnection().getConnectionDetails(); + backend = new AggregationBasicDataset(timer, parameterDetails); + setUp.setUp(null, backend, null, null, null, + false, true, false, false, false); + aggregationConsumerStub = setUp.getAggregationConsumer(); + + // call monitorValue.register with subscription + // subscription= + // - subscriptionId=11 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("11"); + execAndCheckMonitorValueRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + aggregationListener, + System.currentTimeMillis() + TIMEOUT); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AG_1_Basic_Test.class.getName() + " tearDownClass()"); + + // call monitorValue.deregister with subscriptionIds={11} + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + aggregationListener.reset(); + execAndCheckMonitorValueDeregister( + subscriptions, + aggregationListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // update BackendTimer with now + // now=1/1/2025 01:06:00 (ie +6:00) + System.out.println("skip time to 1/1/2025 01:06:00"); + timer.skip(6*60*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1", aggregationVersion=1}: + // - timestamp=? + // - values={{validityState=VALID, rawValue=12.00, convertedValue=null}} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + new ParameterValueData(ValidityState.VALID, + new Union(new Double(12.00)), + null))))); + waitAndCheckForUpdates(aggregationListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * Requires previous execution of Test Case 1. + */ + @Test + public void testCase_02() { + // additional statement for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + // check response as singleton list: + // - aggregationRef={"fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1} + // - timestamp=? + // - parameterValues={{validityState=VALID, rawValue=12.00, convertedValue=null}} + AggregationValueList expected = + new AggregationValueList(new ArrayList<>(Arrays.asList( + new AggregationValue( + AggregationBasicDataset.sat1BcMtq1Ref, + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1200.getValue(), + null)))))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<>(Arrays.asList( + Constant.ID_BC_MTQ1))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_2_Nominal_Values_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_2_Nominal_Values_Test.java new file mode 100755 index 000000000..0cfd4e945 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_2_Nominal_Values_Test.java @@ -0,0 +1,331 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.AggregationListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.AggregationDefaultDataset; +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterDefaultDataset; +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mc.structures.AggregationValue; +import org.ccsds.moims.mo.mc.structures.AggregationValueList; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueDataList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * AG_2_Nominal_Values_Test implements the test scenario #AG-2. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AG_2_Nominal_Values_Test extends AggregationTestClient { + + static AggregationListener aggregationListener = new AggregationListener(); + static Identifier subscriptionId; + + // timeOrigin=1/1/2025 02:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 2, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterDefaultDataset parameterBackend = new ParameterDefaultDataset(timer); + private static AggregationDefaultDataset backend; + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AG_2_Nominal_Values_Test.class.getName())); + setUp.setUp(null, null, null, null, parameterBackend, + false, false, false, false, true); + + if (setUp.getParameterProvider() == null) { + unitTestFail("cannot find the Parameter provider"); + } + SingleConnectionDetails parameterDetails = + setUp.getParameterProvider().getConnection().getConnectionDetails(); + backend = new AggregationDefaultDataset(timer, parameterDetails); + setUp.setUp(null, backend, null, null, null, + false, true, false, false, false); + aggregationConsumerStub = setUp.getAggregationConsumer(); + + // call monitorValue.register with subscription + // subscription= + // - subscriptionId=21 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("21"); + execAndCheckMonitorValueRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + aggregationListener, + System.currentTimeMillis() + TIMEOUT); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AG_2_Nominal_Values_Test.class.getName() + " tearDownClass()"); + + // call monitorValue.deregister with subscriptionIds={21} + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + aggregationListener.reset(); + execAndCheckMonitorValueDeregister( + subscriptions, + aggregationListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test the nominal case for an aggregation value monitoring + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // update BackendTimer with now + // now=1/1/2025 02:10:10 (ie +10:10) + System.out.println("skip time to 1/1/2025 02:10:10"); + timer.skip((10*60+10)*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 2 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1", aggregationVersion=1}: + // - timestamp=?, values={ + // -- {validityState=VALID, rawValue=12.04, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + // - timestamp=?, values={ + // -- {validityState=VALID, rawValue=12.05, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1204.getValue(), + null), + MTQ1ENABLED_ENABLED_VALUE)))), + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1205.getValue(), + null), + MTQ1ENABLED_ENABLED_VALUE)))) + }; + waitAndCheckForUpdates(aggregationListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * test the nominal case for an aggregation getValue + * Requires previous execution of Test Case 1. + */ + @Test + public void testCase_02() { + // additional statement for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // update BackendTimer with now + // now=1/1/2025 02:11:11 (ie +1:01) + System.out.println("skip time to 1/1/2025 02:11:11"); + timer.skip((1*60+1)*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + // check response as singleton list: + // - aggregationRef={"fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1} + // - timestamp=? + // - parameterValues={ + // -- {validityState=VALID, rawValue=12.05, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + AggregationValueList expected = + new AggregationValueList(new ArrayList<>(Arrays.asList( + new AggregationValue( + AggregationDefaultDataset.sat1BcMtq1Ref, + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1205.getValue(), + null), + MTQ1ENABLED_ENABLED_VALUE))))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<>(Arrays.asList( + Constant.ID_BC_MTQ1))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // check no new message from subscription + waitAndCheckNoUpdate(aggregationListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * test getValue with a missing domain + * Requires previous execution of Test Case 2. + */ + @Test + public void testCase_03() { + // additional statement for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // update BackendTimer with now + // now=1/1/2025 02:12:12 (ie +1:01) + System.out.println("skip time to 1/1/2025 02:12:12"); + timer.skip((1*60+1)*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain=null + // - keys={"AGG_BC_MTQ1"} + // check response as singleton list: + // - aggregationRef={"fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1} + // - timestamp=? + // - parameterValues={ + // -- {validityState=VALID, rawValue=12.05, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + AggregationValueList expected = + new AggregationValueList(new ArrayList<>(Arrays.asList( + new AggregationValue( + AggregationDefaultDataset.sat1BcMtq1Ref, + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1205.getValue(), + null), + MTQ1ENABLED_ENABLED_VALUE))))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<>(Arrays.asList( + Constant.ID_BC_MTQ1))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // check no new message from subscription + waitAndCheckNoUpdate(aggregationListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 4. + * test getValue does not impact monitoring + * Requires previous execution of Test Case 3. + */ + @Test + public void testCase_04() { + // additional statement for dependent tests + TestDependency.before(3, this, "testCase_03", 4); + + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // update BackendTimer with now + // now=1/1/2025 02:15:15 (ie +3:03) + System.out.println("skip time to 1/1/2025 02:15:15"); + timer.skip((3*60+3)*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 2 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1", aggregationVersion=1}: + // - timestamp=?, values={ + // -- {validityState=VALID, rawValue=12.11, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1211.getValue(), + null), + MTQ1ENABLED_ENABLED_VALUE)))) + }; + waitAndCheckForUpdates(aggregationListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_3_Report_Config_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_3_Report_Config_Test.java new file mode 100755 index 000000000..558bd760c --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_3_Report_Config_Test.java @@ -0,0 +1,866 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.AggregationListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.AggregationDatasetForReportConfig; +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterDatasetForReportConfig; +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueDataList; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * AG_3_Report_Config_Test implements the test scenario #AG-3. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AG_3_Report_Config_Test extends AggregationTestClient { + + static AggregationListener aggregationListener = new AggregationListener(); + static Identifier subscriptionId; + + // timeOrigin=1/1/2025 03:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 3, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterDatasetForReportConfig parameterBackend = new ParameterDatasetForReportConfig(timer); + private static AggregationDatasetForReportConfig backend; + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AG_3_Report_Config_Test.class.getName())); + setUp.setUp(null, null, null, null, parameterBackend, + false, false, false, false, true); + + if (setUp.getParameterProvider() == null) { + unitTestFail("cannot find the Parameter provider"); + } + SingleConnectionDetails parameterDetails = + setUp.getParameterProvider().getConnection().getConnectionDetails(); + backend = new AggregationDatasetForReportConfig(timer, parameterDetails); + setUp.setUp(null, backend, null, null, null, + false, true, false, false, false); + aggregationConsumerStub = setUp.getAggregationConsumer(); + + // call monitorValue.register with subscription + // subscription= + // - subscriptionId=31 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("31"); + execAndCheckMonitorValueRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + aggregationListener, + System.currentTimeMillis() + TIMEOUT); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AG_3_Report_Config_Test.class.getName() + " tearDownClass()"); + + // call monitorValue.deregister with subscriptionIds={31} + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + aggregationListener.reset(); + execAndCheckMonitorValueDeregister( + subscriptions, + aggregationListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test the nominal case for an aggregation getReportingConfiguration + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=301s} + // - {reportingEnabled=false, reportInterval=301s} + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_301), + new ReportConfiguration( + false, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * test the nominal case for an aggregation enableReporting + * Requires previous execution of Test Case 1. + */ + @Test + public void testCase_02() { + // additional statement for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // update BackendTimer with now-1 + // now-1=1/1/2025 03:01:01 (ie +1:01) + System.out.println("skip time to 1/1/2025 03:01:01"); + timer.skip((1*60+1)*1000); + + // check no new message from subscription + waitAndCheckNoUpdate(aggregationListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // call enableReporting with enableReportParams + // enableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + aggregationListener.reset(); + execAndCheckEnableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1_REV", parameterVersion=1}: + // - timestamp=1/1/2025 03:01:01, values={ + // -- {validityState=INVALID_RAW, rawValue=null, convertedValue=null} + // -- {validityState=INVALID_RAW, rawValue=null, convertedValue=null}} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + INVALID_RAW_VALUE, + INVALID_RAW_VALUE)))) +// new ParameterValueDataList(new ArrayList<>(Arrays.asList( +// MTQ1ENABLED_ENABLED_VALUE, +// new ParameterValueData(ValidityState.VALID, +// NA_DOUBLE_1200.getValue(), +// null))))) + }; + waitAndCheckForUpdates(aggregationListener, startTime + TIMEOUT, targetUpdates); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=301s} + // - {reportingEnabled=true, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_301), + new ReportConfiguration( + true, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now-2 + // now-2=1/1/2025 03:05:05 (ie +4:04) + aggregationListener.reset(); + System.out.println("skip time to 1/1/2025 03:05:05"); + timer.skip((4*60+4)*1000); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1", parameterVersion=1}: + // - timestamp=1/1/2025 03:05:05, values={ + // -- {validityState=VALID, rawValue=12.00, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + targetUpdates = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1200.getValue(), + null), + MTQ1ENABLED_ENABLED_VALUE)))) + }; + waitAndCheckForUpdates(aggregationListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * test the nominal case for an aggregation disableReporting + * Requires previous execution of Test Case 2. + */ + @Test + public void testCase_03() { + // additional statement for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call disableReporting with disableReportParams + // disableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1_REV"} + execAndCheckDisableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=301s} + // - {reportingEnabled=false, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_301), + new ReportConfiguration( + false, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 03:10:10 (ie +5:05) + aggregationListener.reset(); + System.out.println("skip time to 1/1/2025 03:10:10"); + timer.skip((5*60+5)*1000); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1", parameterVersion=1}: + // - timestamp=1/1/2025 03:05:05, values={ + // -- {validityState=VALID, rawValue=12.05, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1205.getValue(), + null), + MTQ1ENABLED_ENABLED_VALUE)))) + }; + waitAndCheckForUpdates(aggregationListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 4. + * test disableReporting with null keys + * Requires previous execution of Test Case 3. + */ + @Test + public void testCase_04() { + // additional statement for dependent tests + TestDependency.before(3, this, "testCase_03", 4); + + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call disableReporting with disableReportParams + // disableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + execAndCheckDisableReporting( + Constant.DOMAIN_SAT1, + null, + aggregationListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=false, reportInterval=301s} + // - {reportingEnabled=false, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + false, + DURATION_301), + new ReportConfiguration( + false, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 03:11:11 (ie +1:01) + System.out.println("skip time to 1/1/2025 03:11:11"); + timer.skip((1*60+1)*1000); + + // check no new message from subscription + waitAndCheckNoUpdate(aggregationListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 5. + * test enableReporting with null keys + * Requires previous execution of Test Case 4. + */ + @Test + public void testCase_05() { + // additional statement for dependent tests + TestDependency.before(4, this, "testCase_04", 5); + + System.out.println("Running: testCase_05()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call enableReporting with enableReportParams + // enableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + execAndCheckEnableReporting( + Constant.DOMAIN_SAT1, + null, + aggregationListener, + startTime + TIMEOUT); + + // check reception of 2 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1", order not relevant, + // 1 with keys={parameterKey="AGG_BC_MTQ1", parameterVersion=1}: + // - timestamp=1/1/2025 03:11:11, values={ + // -- {validityState=VALID, rawValue=12.05, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + // 1 with keys={parameterKey="AGG_BC_MTQ1_REV", parameterVersion=1}: + // - timestamp=1/1/2025 03:11:11, values={ + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"} + // -- {validityState=VALID, rawValue=12.05, convertedValue=null}} + ParameterValueData mtq1VoltageValue = new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1205.getValue(), + null); + MonitorValueUpdate[][] targetUpdates = new MonitorValueUpdate[2][]; + targetUpdates[0] = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + mtq1VoltageValue, + MTQ1ENABLED_ENABLED_VALUE)))) + }; + targetUpdates[1] = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + MTQ1ENABLED_ENABLED_VALUE, + mtq1VoltageValue)))) + }; + waitAndCheckForUpdates(aggregationListener, startTime + TIMEOUT, targetUpdates); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=301s} + // - {reportingEnabled=true, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_301), + new ReportConfiguration( + true, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 03:15:15 (ie +4:04) + System.out.println("skip time to 1/1/2025 03:15:15"); + timer.skip((4*60+4)*1000); + + // check no new message from subscription + waitAndCheckNoUpdate(aggregationListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 6. + * test the nominal case for an aggregation setReportingPeriod + * Requires previous execution of Test Case 5. + */ + @Test + public void testCase_06() { + // additional statement for dependent tests + TestDependency.before(5, this, "testCase_05", 6); + + System.out.println("Running: testCase_06()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call setReportingPeriod with setReportParams + // setReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + // - reportInterval=602s + execAndCheckSetReportingPeriod( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1))), + DURATION_602, + aggregationListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=602s} + // - {reportingEnabled=true, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_602), + new ReportConfiguration( + true, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now-1 + // now-1=1/1/2025 03:20:20 (ie +5:05) + aggregationListener.reset(); + System.out.println("skip time to 1/1/2025 03:20:20"); + timer.skip((5*60+5)*1000); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1_REV", parameterVersion=1}: + // - timestamp=1/1/2025 03:16:16, values={ + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"} + // -- {validityState=VALID, rawValue=12.10, convertedValue=null}} + waitAndCheckForUpdates( + aggregationListener, + startTime + TIMEOUT, + new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + MTQ1ENABLED_ENABLED_VALUE, + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1210.getValue(), + null))))) + }); + + // update BackendTimer with now-2 + // now-2=1/1/2025 03:21:21 (ie +1:01) + aggregationListener.reset(); + System.out.println("skip time to 1/1/2025 03:21:21"); + timer.skip((1*60+1)*1000); + + // check reception of 2 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1", order not relevant, + // 1 with keys={parameterKey="AGG_BC_MTQ1", parameterVersion=1}: + // - timestamp=1/1/2025 03:21:21, values={ + // -- {validityState=VALID, rawValue=12.15, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + // 1 with keys={parameterKey="AGG_BC_MTQ1_REV", parameterVersion=1}: + // - timestamp=1/1/2025 03:21:21, values={ + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"} + // -- {validityState=VALID, rawValue=12.15, convertedValue=null}} + ParameterValueData mtq1VoltageValue = new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1215.getValue(), + null); + MonitorValueUpdate[][] targetUpdates = new MonitorValueUpdate[2][]; + targetUpdates[0] = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + mtq1VoltageValue, + MTQ1ENABLED_ENABLED_VALUE)))) + }; + targetUpdates[1] = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + MTQ1ENABLED_ENABLED_VALUE, + mtq1VoltageValue)))) + }; + waitAndCheckForUpdates( + aggregationListener, + startTime + TIMEOUT, + targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 7. + * test setReportingPeriod of a disabled aggregation + * Requires previous execution of Test Case 6. + */ + @Test + public void testCase_07() { + // additional statement for dependent tests + TestDependency.before(6, this, "testCase_06", 7); + + System.out.println("Running: testCase_07()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call disableReporting with disableReportParams + // disableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + execAndCheckDisableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1))), + aggregationListener, + startTime + TIMEOUT); + + // call setReportingPeriod with setReportParams + // setReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + // - reportInterval=120s + aggregationListener.reset(); + execAndCheckSetReportingPeriod( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1))), + DURATION_120, + aggregationListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=false, reportInterval=120s} + // - {reportingEnabled=true, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + false, + DURATION_120), + new ReportConfiguration( + true, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now-1 + // now-1=1/1/2025 03:22:22 (ie +1:01) + System.out.println("skip time to 1/1/2025 03:22:22"); + timer.skip((1*60+1)*1000); + + // check no new message from subscription + waitAndCheckNoUpdate(aggregationListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // call enableReporting with enableReportParams + // enableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + aggregationListener.reset(); + execAndCheckEnableReporting( + Constant.DOMAIN_SAT1, + null, + aggregationListener, + startTime + TIMEOUT); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1", parameterVersion=1}: + // - timestamp=1/1/2025 03:22:22, values={ + // -- {validityState=VALID, rawValue=12.15, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + ParameterValueData mtq1VoltageValue = new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1215.getValue(), + null); + waitAndCheckForUpdates( + aggregationListener, + startTime + TIMEOUT, + new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + mtq1VoltageValue, + MTQ1ENABLED_ENABLED_VALUE)))) + }); + + // update BackendTimer with now-2 + // now-2=1/1/2025 03:24:24 (ie +2:02) + aggregationListener.reset(); + System.out.println("skip time to 1/1/2025 03:24:24"); + timer.skip((2*60+2)*1000); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1", parameterVersion=1}: + // - timestamp=1/1/2025 03:24:22, values={ + // -- {validityState=VALID, rawValue=12.15, convertedValue=null} + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}} + waitAndCheckForUpdates( + aggregationListener, + startTime + TIMEOUT, + new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + mtq1VoltageValue, + MTQ1ENABLED_ENABLED_VALUE)))) + }); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 8. + * test setReportingPeriod with value 0 + * Requires previous execution of Test Case 7. + */ + @Test + public void testCase_08() { + // additional statement for dependent tests + TestDependency.before(7, this, "testCase_07", 8); + + System.out.println("Running: testCase_08()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call setReportingPeriod with setReportParams + // setReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + // - reportInterval=0s + execAndCheckSetReportingPeriod( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1))), + DURATION_0, + aggregationListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=0s} + // - {reportingEnabled=true, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_0), + new ReportConfiguration( + true, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 03:26:26 (ie +2:02) + System.out.println("skip time to 1/1/2025 03:26:26"); + timer.skip((2*60+2)*1000); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1_REV", parameterVersion=1}: + // - timestamp=1/1/2025 03:26:26, values={ + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"} + // -- {validityState=VALID, rawValue=12.20, convertedValue=null}} + waitAndCheckForUpdates( + aggregationListener, + startTime + TIMEOUT, + new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + MTQ1ENABLED_ENABLED_VALUE, + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1220.getValue(), + null))))) + }); + + // additional statement for dependent tests + TestDependency.after(); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_4_Dynamic_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_4_Dynamic_Test.java new file mode 100755 index 000000000..250a5732f --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_4_Dynamic_Test.java @@ -0,0 +1,603 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.AggregationListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.AggregationDatasetForReportConfig; +import org.ccsds.mo.mc.testbed.backends.AggregationDynamicDataset; +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterDatasetForReportConfig; +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.ObjectRefList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mc.structures.AggregationDefinition; +import org.ccsds.moims.mo.mc.structures.AggregationDefinitionList; +import org.ccsds.moims.mo.mc.structures.AggregationValue; +import org.ccsds.moims.mo.mc.structures.AggregationValueList; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueDataList; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * AG_4_Dynamic_Test implements the test scenario #AG-4. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AG_4_Dynamic_Test extends AggregationTestClient { + + static AggregationListener aggregationListener = new AggregationListener(); + static Identifier subscriptionId; + + // timeOrigin=1/1/2025 04:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 4, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterDatasetForReportConfig parameterBackend = new ParameterDatasetForReportConfig(timer); + private static AggregationDynamicDataset backend; + + public static final ObjectRef dynSat1BcMtq1RevRef = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1_REV, + new UInteger(1)); + public static final AggregationDefinition dynSat1BcMtq1RevDefinition = + new AggregationDefinition( + getAggregationIdentity(dynSat1BcMtq1RevRef), + "", + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDatasetForReportConfig.sat1Mtq1EnabledRef, + ParameterDatasetForReportConfig.sat1Mtq1VoltageRef)))); + + public static final ObjectRef dynSat1BcMtq1Ref = + new ObjectRef<>( + Constant.DOMAIN_SAT1, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1, + new UInteger(1)); + public static final AggregationDefinition dynSat1BcMtq1Definition = + new AggregationDefinition( + getAggregationIdentity(dynSat1BcMtq1Ref), + "", + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDatasetForReportConfig.sat1Mtq1VoltageRef)))); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AG_4_Dynamic_Test.class.getName())); + setUp.setUp(null, null, null, null, parameterBackend, + false, false, false, false, true); + + if (setUp.getParameterProvider() == null) { + unitTestFail("cannot find the Parameter provider"); + } + SingleConnectionDetails parameterDetails = + setUp.getParameterProvider().getConnection().getConnectionDetails(); + backend = new AggregationDynamicDataset(timer, parameterDetails); + setUp.setUp(null, backend, null, null, null, + false, true, false, false, false); + aggregationConsumerStub = setUp.getAggregationConsumer(); + + // call monitorValue.register with subscription + // subscription= + // - subscriptionId=41 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("41"); + execAndCheckMonitorValueRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + aggregationListener, + System.currentTimeMillis() + TIMEOUT); + + // update BackendTimer with now + // now=1/1/2025 04:06:06 (ie +6:06) + System.out.println("skip time to 1/1/2025 04:06:06"); + timer.skip((6*60+6)*1000); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AG_4_Dynamic_Test.class.getName() + " tearDownClass()"); + + // call monitorValue.deregister with subscriptionIds={41} + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + aggregationListener.reset(); + execAndCheckMonitorValueDeregister( + subscriptions, + aggregationListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test the nominal case for an aggregation listDefinition + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call listDefinition with listDefinitionParams + // listDefinitionParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + // check response as singleton list: + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1}} + AggregationDefinitionList expected = + new AggregationDefinitionList(new ArrayList<> (Arrays.asList( + new AggregationDefinition( + getAggregationIdentity(AggregationDynamicDataset.sat1BcMtq1Ref), + "", + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDatasetForReportConfig.sat1Mtq1VoltageRef, + ParameterDatasetForReportConfig.sat1Mtq1EnabledRef))))))); + execAndCheckListDefinition( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * test listDefinition with null keys + * Requires previous execution of Test Case 1 (not true). + */ + @Test + public void testCase_02() { + // additional statement for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call listDefinition with listDefinitionParams + // listDefinitionParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + // check response as singleton list: + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1}} + AggregationDefinitionList expected = + new AggregationDefinitionList(new ArrayList<> (Arrays.asList( + new AggregationDefinition( + getAggregationIdentity(AggregationDynamicDataset.sat1BcMtq1Ref), + "", + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDatasetForReportConfig.sat1Mtq1VoltageRef, + ParameterDatasetForReportConfig.sat1Mtq1EnabledRef))))))); + execAndCheckListDefinition( + Constant.DOMAIN_SAT1, + null, + aggregationListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * test the nominal case for an aggregation addAggregation + * Requires previous execution of Test Case 2 (not true). + */ + @Test + public void testCase_03() { + // additional statement for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call addAggregation with addAggregParams + // addAggregParams={ + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}}} + execAndCheckAddAggregation( + new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + dynSat1BcMtq1RevDefinition))), + aggregationListener, + startTime + TIMEOUT); + + // call listDefinition with listDefinitionParams + // listDefinitionParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + // check response, order not relevant: + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1}} + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}} + aggregationListener.reset(); + AggregationDefinitionList expected = + new AggregationDefinitionList(new ArrayList<> (Arrays.asList( + new AggregationDefinition( + getAggregationIdentity(AggregationDynamicDataset.sat1BcMtq1Ref), + "", + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterDatasetForReportConfig.sat1Mtq1VoltageRef, + ParameterDatasetForReportConfig.sat1Mtq1EnabledRef)))), + dynSat1BcMtq1RevDefinition))); + execAndCheckListDefinition( + Constant.DOMAIN_SAT1, + null, + aggregationListener, + startTime + TIMEOUT, + expected); + + // keep track of the order of the returned keys for next test + test4Expected = new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + aggregationListener.listDefinitionResponse.get(1), + aggregationListener.listDefinitionResponse.get(0)))); + + // additional statement for dependent tests + TestDependency.after(); + } + + private static AggregationDefinitionList test4Expected; + /** + * Test Case 4. + * test order of listDefinition result + * Requires previous execution of Test Case 3. + */ + @Test + public void testCase_04() { + // additional statement for dependent tests + TestDependency.before(3, this, "testCase_03", 4); + if (test4Expected == null) + throw new IllegalStateException("test4KeysOrder not set"); + + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call listDefinition with listDefinitionParams + // listDefinitionParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1_REV", "AGG_BC_MTQ1"}* + // check response, order is relevant*: + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}} + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1}} + // *order of keys and result is reverse of order returned by listDefinition in UC 3 above + execAndCheckListDefinition( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + test4Expected.get(0).getObjectIdentity().getKey(), + test4Expected.get(1).getObjectIdentity().getKey()))), + aggregationListener, + startTime + TIMEOUT, + test4Expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 5. + * test enableReporting with null keys + * Requires previous execution of Test Case 4. + */ + @Test + public void testCase_05() { + // additional statement for dependent tests + TestDependency.before(4, this, "testCase_04", 5); + + System.out.println("Running: testCase_05()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // update BackendTimer with now + // now=1/1/2025 04:08:08 (ie +2:02) + System.out.println("skip time to 1/1/2025 04:08:08"); + timer.skip((2*60+2)*1000); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={parameterKey="AGG_BC_MTQ1_REV", parameterVersion=1}: + // - timestamp=1/1/2025 04:08:06, values={ + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"} + // -- {validityState=VALID, rawValue=12.00, convertedValue=null}} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + MTQ1ENABLED_ENABLED_VALUE, + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1200.getValue(), + null))))) + }; + waitAndCheckForUpdates(aggregationListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 6. + * test the nominal case for an aggregation removeAggregation + * Requires previous execution of Test Case 5. + */ + @Test + public void testCase_06() { + // additional statement for dependent tests + TestDependency.before(5, this, "testCase_05", 6); + + System.out.println("Running: testCase_06()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call removeAggregation with removeAggregParams + // removeAggregParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + execAndCheckRemoveAggregation( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1))), + aggregationListener, + startTime + TIMEOUT); + + // call listDefinition with listDefinitionParams + // listDefinitionParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + // check response as singleton list: + // - identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1_REV", version=1) + // - description: "" + // - category: null + // - parameters: { + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1} + // -- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}} + aggregationListener.reset(); + AggregationDefinitionList expected = + new AggregationDefinitionList(new ArrayList<> (Arrays.asList( + dynSat1BcMtq1RevDefinition))); + execAndCheckListDefinition( + Constant.DOMAIN_SAT1, + null, + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 04:10:10 (ie +2:02) + aggregationListener.reset(); + System.out.println("skip time to 1/1/2025 04:10:10"); + timer.skip((2*60+2)*1000); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={aggregationKey="AGG_BC_MTQ1_REV", parameterVersion=1}: + // - timestamp=1/1/2025 04:10:06, values={ + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"} + // -- {validityState=VALID, rawValue=12.05, convertedValue=null}} + waitAndCheckForUpdates( + aggregationListener, + startTime + TIMEOUT, + new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + MTQ1ENABLED_ENABLED_VALUE, + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1205.getValue(), + null))))) + }); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 7. + * test reusing an aggregation key + * Requires previous execution of Test Case 6. + */ + @Test + public void testCase_07() { + // additional statement for dependent tests + TestDependency.before(6, this, "testCase_06", 7); + + System.out.println("Running: testCase_07()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call addAggregation with addAggregParams + // addAggregParams={ + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}}} + execAndCheckAddAggregation( + new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + dynSat1BcMtq1Definition))), + aggregationListener, + startTime + TIMEOUT); + + // call listDefinition with listDefinitionParams + // listDefinitionParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + // check response, order not relevant: + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}} + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1ENABLED", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}} + aggregationListener.reset(); + AggregationDefinitionList expected = + new AggregationDefinitionList(new ArrayList<> (Arrays.asList( + dynSat1BcMtq1Definition, + dynSat1BcMtq1RevDefinition))); + execAndCheckListDefinition( + Constant.DOMAIN_SAT1, + null, + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 04:12:12 (ie +2:02) + aggregationListener.reset(); + System.out.println("skip time to 1/1/2025 04:12:12"); + timer.skip((2*60+2)*1000); + + // check reception of 2 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1", order not relevant, + // 1 with keys={parameterKey="AGG_BC_MTQ1", parameterVersion=1}: + // - timestamp=1/1/2025 03:11:11, values={ + // -- {validityState=VALID, rawValue=12.05, convertedValue=null}} + // 1 with keys={parameterKey="AGG_BC_MTQ1_REV", parameterVersion=1}: + // - timestamp=1/1/2025 03:11:11, values={ + // -- {validityState=VALID, rawValue=1, convertedValue="ENABLED"} + // -- {validityState=VALID, rawValue=12.05, convertedValue=null}} + ParameterValueData mtq1VoltageValue = new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1205.getValue(), + null); + MonitorValueUpdate[][] targetUpdates = new MonitorValueUpdate[][] { + new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + mtq1VoltageValue)))) + }, + new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_BC_MTQ1_REV, + new UInteger(1), + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + MTQ1ENABLED_ENABLED_VALUE, + mtq1VoltageValue)))) + }}; + waitAndCheckForUpdates(aggregationListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_9_Errors_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_9_Errors_Test.java new file mode 100755 index 000000000..831398b36 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AG_9_Errors_Test.java @@ -0,0 +1,835 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.AggregationListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.AggregationDatasetForReportConfig; +import org.ccsds.mo.mc.testbed.backends.AggregationDefaultDataset; +import org.ccsds.mo.mc.testbed.backends.AggregationDynamicDataset; +import org.ccsds.mo.mc.testbed.backends.AggregationErrorDataset; +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterDatasetForReportConfig; +import org.ccsds.mo.mc.testbed.backends.ParameterErrorDataset; +import org.ccsds.moims.mo.mal.MALHelper; +import org.ccsds.moims.mo.mal.helpertools.connections.SingleConnectionDetails; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.ObjectRefList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mc.MCHelper; +import org.ccsds.moims.mo.mc.structures.AggregationDefinition; +import org.ccsds.moims.mo.mc.structures.AggregationDefinitionList; +import org.ccsds.moims.mo.mc.structures.AggregationValue; +import org.ccsds.moims.mo.mc.structures.AggregationValueList; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueDataList; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * AG_9_Errors_Test implements the test scenario #AG-9. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AG_9_Errors_Test extends AggregationTestClient { + + static AggregationListener aggregationListener = new AggregationListener(); + static Identifier subscriptionId; + + // timeOrigin=1/1/2025 09:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 9, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterErrorDataset parameterBackend = new ParameterErrorDataset(timer); + private static AggregationErrorDataset backend; + + public static final ParameterValueData MTQ1ENABLED_ENABLED_VALUE = + new ParameterValueData( + ValidityState.VALID, + NA_UINT_1.getValue(), + NA_STRING_ENABLED.getValue()); + public static final ParameterValueData MTQ1ENABLED_EXPIRED_VALUE = + new ParameterValueData( + ValidityState.EXPIRED, + NA_UINT_1.getValue(), + NA_STRING_ENABLED.getValue()); + + public static final ObjectRef dynSat2BcMtq1RevRef = + new ObjectRef<>( + Constant.DOMAIN_SAT2, + AggregationDefinition.TYPE_ID.getTypeId(), + Constant.ID_BC_MTQ1_REV, + new UInteger(1)); + public static final AggregationDefinition dynSat2BcMtq1RevDefinition = + new AggregationDefinition( + getAggregationIdentity(dynSat2BcMtq1RevRef), + "", + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterErrorDataset.sat2Mtq1VoltageRef, + ParameterErrorDataset.sat1Mtq1VoltageRef)))); + +// public static final ObjectRef dynSat1BcMtq1Ref = +// new ObjectRef<>( +// Constant.DOMAIN_SAT1, +// AggregationDefinition.TYPE_ID.getTypeId(), +// Constant.ID_BC_MTQ1, +// new UInteger(1)); +// public static final AggregationDefinition dynSat1BcMtq1Definition = +// new AggregationDefinition( +// getAggregationIdentity(dynSat1BcMtq1Ref), +// "", +// null, +// new ObjectRefList(new ArrayList<> (Arrays.asList( +// ParameterErrorDataset.sat1Mtq1VoltageRef)))); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AG_9_Errors_Test.class.getName())); + setUp.setUp(null, null, null, null, parameterBackend, + false, false, false, false, true); + + if (setUp.getParameterProvider() == null) { + unitTestFail("cannot find the Parameter provider"); + } + SingleConnectionDetails parameterDetails = + setUp.getParameterProvider().getConnection().getConnectionDetails(); + backend = new AggregationErrorDataset(timer, parameterDetails); + setUp.setUp(null, backend, null, null, null, + false, true, false, false, false); + aggregationConsumerStub = setUp.getAggregationConsumer(); + + long startTime = System.currentTimeMillis(); + + // call monitorValue.register with subscription + // subscription= + // - subscriptionId=91 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("91"); + execAndCheckMonitorValueRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + aggregationListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=301s} + // - {reportingEnabled=false, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_301), + new ReportConfiguration( + false, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 09:06:00 (ie +6:00) + System.out.println("skip time to 1/1/2025 09:06:00"); + timer.skip(6*60*1000); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AG_9_Errors_Test.class.getName() + " tearDownClass()"); + + // call monitorValue.deregister with subscriptionIds={41} + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + aggregationListener.reset(); + execAndCheckMonitorValueDeregister( + subscriptions, + aggregationListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test ambiguity with a null domain in getValue + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call getValue with getValueParams + // getValueParams= + // - domain=null + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check ERROR message with code Ambiguous + // check the extraInfo field as a singleton list holding element 0 + execAndCheckErrorGetValue( + null, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + MCHelper.AMBIGUOUS_ERROR_NUMBER, + EXTRA_UIL_0); + + } + + /** + * Test Case 2. + * test unknown parameter in getValue + */ + @Test + public void testCase_02() { + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat2" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 1 + execAndCheckErrorGetValue( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_1); + + // call addAggregation with addAggregParams + // addAggregParams={ + // - { + // -- identity: ("fr.cnes.mission.sat2", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat2", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}}} + aggregationListener.reset(); + execAndCheckAddAggregation( + new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + dynSat2BcMtq1RevDefinition))), + aggregationListener, + startTime + TIMEOUT); + + // call getValue with getValueParams + // check response as list of 2 items: + // - { + // -- aggregationRef={"fr.cnes.mission.sat2", "AGG_BC_MTQ1", version=1} + // -- timestamp=1/1/2025 09:01:00 + // -- parameterValues={ + // --- {validityState=VALID, rawValue=12.00, convertedValue=null} + // --- {validityState=VALID, rawValue=22.00, convertedValue=null} + // --- {validityState=VALID, rawValue=1, convertedValue="ENABLED"}}} + // - { + // -- aggregationRef={"fr.cnes.mission.sat2", "AGG_BC_MTQ1_REV", version=1} + // -- timestamp=1/1/2025 02:11:00 + // -- parameterValues={ + // --- {validityState=VALID, rawValue=22.00, convertedValue=null} + // --- {validityState=VALID, rawValue=12.00, convertedValue=null}}} + aggregationListener.reset(); + AggregationValueList expected = + new AggregationValueList(new ArrayList<>(Arrays.asList( + new AggregationValue( + AggregationErrorDataset.sat2BcMtq1Ref, + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + MTQ1VOLTAGE_1200_VALUE, + MTQ1VOLTAGE_2200_VALUE, + MTQ1ENABLED_ENABLED_VALUE)))), + new AggregationValue( + dynSat2BcMtq1RevRef, + null, // timestamp, unchecked + new ParameterValueDataList(new ArrayList<>(Arrays.asList( + MTQ1VOLTAGE_2200_VALUE, + MTQ1VOLTAGE_1200_VALUE))))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + // call removeAggregation with removeAggregParams + // removeAggregParams= + // - domain="fr.cnes.mission.sat2" + // - keys={"AGG_BC_MTQ1_REV"} + aggregationListener.reset(); + execAndCheckRemoveAggregation( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT); + + // call getValue with getValueParams + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 1 + aggregationListener.reset(); + execAndCheckErrorGetValue( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_1); + + } + + /** + * Test Case 3. + * test inconsistent parameters in setReportingPeriod + */ + @Test + public void testCase_03() { + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call setReportingPeriod with setReportParams + // setReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + // - reportInterval=-1s + // check ERROR message with code Invalid + execAndCheckErrorSetReportingPeriod( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1))), + DURATION__1, + aggregationListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + null); + + } + + /** + * Test Case 4. + * test an invalid identity in addAggregation + */ + @Test + public void testCase_04() { + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call addAggregation with addAggregParams + // addAggregParams={ + // - { + // -- identity: ("fr.cnes.mission.sat2", "INVALID_ID", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat2", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}}} + // check ERROR message with code Invalid + // check the extraInfo field as a singleton list holding element 0 + execAndCheckErrorAddAggregation( + new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + new AggregationDefinition( + new ObjectIdentity( + Constant.DOMAIN_SAT2, + new Identifier("INVALID_ID"), + new UInteger(1)), + "", + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterErrorDataset.sat2Mtq1VoltageRef, + ParameterErrorDataset.sat1Mtq1VoltageRef))))))), + aggregationListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + EXTRA_UIL_0); + + } + + /** + * Test Case 5. + * test a duplicate identity in addAggregation + */ + @Test + public void testCase_05() { + System.out.println("Running: testCase_05()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call addAggregation with addAggregParams + // addAggregParams={ + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat2", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}}} + // check ERROR message with code Invalid + // check the extraInfo field as a singleton list holding element 0 + execAndCheckErrorAddAggregation( + new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + new AggregationDefinition( + getAggregationIdentity(AggregationErrorDataset.sat1BcMtq1Ref), + "", + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterErrorDataset.sat2Mtq1VoltageRef, + ParameterErrorDataset.sat1Mtq1VoltageRef))))))), + aggregationListener, + startTime + TIMEOUT, + MCHelper.DUPLICATE_ERROR_NUMBER, + EXTRA_UIL_0); + + } + + /** + * Test Case 6. + * test atomicity of enableReporting operation + */ + @Test + public void testCase_06() { + System.out.println("Running: testCase_06()"); + long + startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call enableReporting with enableReportParams + // enableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"UNKNOWN", "AGG_BC_MTQ1_REV"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 0 + execAndCheckErrorEnableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_UNKNOWN, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_0); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1_REV"} + // check response as a singleton list: + // - {reportingEnabled=false, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + false, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + } + + /** + * Test Case 7. + * test atomicity of disableReporting operation + */ + @Test + public void testCase_07() { + System.out.println("Running: testCase_07()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call disableReporting with disableReportParams + // disableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "UNKNOWN"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 1 + execAndCheckErrorEnableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_UNKNOWN))), + aggregationListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_1); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1"} + // check response as a singleton list: + // - {reportingEnabled=true, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1))), + aggregationListener, + startTime + TIMEOUT, + expected); + + } + + /** + * Test Case 8. + * test atomicity of setReportingPeriod operation + */ + @Test + public void testCase_08() { + System.out.println("Running: testCase_08()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call setReportingPeriod with setReportParams + // setReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // - reportInterval=-1s + // check ERROR message with code Invalid + // check the extraInfo field as list of 2 items: {0, 1} + execAndCheckErrorSetReportingPeriod( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + DURATION__1, + aggregationListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + new UIntegerList(new ArrayList<>(Arrays.asList( + new UInteger(0), + new UInteger(1))))); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=301s} + // - {reportingEnabled=false, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_301), + new ReportConfiguration( + false, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + expected); + + } + + /** + * Test Case 9. + * test atomicity of addAggregation operation + */ + @Test + public void testCase_09() { + System.out.println("Running: testCase_09()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call addAggregation with addAggregParams + // addAggregParams={ + // - { + // -- identity: ("fr.cnes.mission.sat2", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat2", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}} + // - { + // -- identity: ("fr.cnes.mission.sat1", "AGG_BC_MTQ1", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat2", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}}} + // check ERROR message with code Duplicate + // check the extraInfo field as a singleton list holding element 1 + execAndCheckErrorAddAggregation( + new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + dynSat2BcMtq1RevDefinition, + new AggregationDefinition( + getAggregationIdentity(AggregationErrorDataset.sat1BcMtq1Ref), + "", + null, + new ObjectRefList(new ArrayList<> (Arrays.asList( + ParameterErrorDataset.sat2Mtq1VoltageRef, + ParameterErrorDataset.sat1Mtq1VoltageRef))))))), + aggregationListener, + startTime + TIMEOUT, + MCHelper.DUPLICATE_ERROR_NUMBER, + EXTRA_UIL_1); + + // call listDefinition with listDefinitionParams + // listDefinitionParams= + // - domain="fr.cnes.mission.sat2" + // - keys={"AGG_BC_MTQ1_REV"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 0 + aggregationListener.reset(); + execAndCheckErrorListDefinition( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_0); + + } + + /** + * Test Case 10. + * test atomicity of removeAggregation operation + */ + @Test + public void testCase_10() { + System.out.println("Running: testCase_10()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call removeAggregation with removeAggregParams + // removeAggregParams={ + // - domain="fr.cnes.mission.sat2" + // - keys={"AGG_BC_MTQ1", "AGG_BC_MTQ1_REV"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 1 + execAndCheckErrorRemoveAggregation( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1, + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_1); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat2" + // - keys={"AGG_BC_MTQ1"} + // check response as singleton list: + // - {reportingEnabled=false, reportInterval=301s} + aggregationListener.reset(); + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + false, + DURATION_301)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1))), + aggregationListener, + startTime + TIMEOUT, + expected); + + } + + /** + * Test Case 11. + * test an invalid value for category + */ + @Test + public void testCase_11() { + System.out.println("Running: testCase_11()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call addAggregation with addAggregParams + // addAggregParams={ + // - { + // -- identity: ("fr.cnes.mission.sat2", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: "UNKNOWN CATEGORY" + // -- parameters: { + // --- {domain="fr.cnes.mission.sat2", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}}} + // check ERROR message with code Invalid + // check the extraInfo field as a singleton list holding element 0 + execAndCheckErrorAddAggregation( + new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + new AggregationDefinition( + dynSat2BcMtq1RevDefinition.getObjectIdentity(), + "", + new Identifier("UNKNOWN CATEGORY"), + dynSat2BcMtq1RevDefinition.getParameters())))), + aggregationListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + EXTRA_UIL_0); + + } + + /** + * Test Case 12. + * test an empty parameters list + */ + @Test + public void testCase_12() { + System.out.println("Running: testCase_12()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call addAggregation with addAggregParams + // addAggregParams={ + // - { + // -- identity: ("fr.cnes.mission.sat2", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: null + // -- parameters: {}} + // check ERROR message with code Invalid + // check the extraInfo field as a singleton list holding element 0 + execAndCheckErrorAddAggregation( + new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + new AggregationDefinition( + dynSat2BcMtq1RevDefinition.getObjectIdentity(), + "", + null, + new ObjectRefList())))), + aggregationListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + EXTRA_UIL_0); + + } + + /** + * Test Case 13. + * test a duplicate identity in addAggregation + */ + @Test + public void testCase_13() { + System.out.println("Running: testCase_13()"); + long startTime = System.currentTimeMillis(); + + aggregationListener.reset(); + // call addAggregation with addAggregParams + // addAggregParams={ + // - { + // -- identity: ("fr.cnes.mission.sat2", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat2", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}} + // - { + // -- identity: ("fr.cnes.mission.sat2", "AGG_BC_MTQ1_REV", version=1) + // -- description: "" + // -- category: null + // -- parameters: { + // --- {domain="fr.cnes.mission.sat2", key="ATT_BC_MTQ1VOLTAGE", version=1} + // --- {domain="fr.cnes.mission.sat1", key="ATT_BC_MTQ1VOLTAGE", version=1}}} + // check ERROR message with code Duplicate + // check the extraInfo field as a singleton list holding element 1 + execAndCheckErrorAddAggregation( + new AggregationDefinitionList(new ArrayList<>(Arrays.asList( + dynSat2BcMtq1RevDefinition, + dynSat2BcMtq1RevDefinition))), + aggregationListener, + startTime + TIMEOUT, + MCHelper.DUPLICATE_ERROR_NUMBER, + EXTRA_UIL_1); + + // call listDefinition with listDefinitionParams + // listDefinitionParams= + // - domain="fr.cnes.mission.sat2" + // - keys={"AGG_BC_MTQ1_REV"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 0 + aggregationListener.reset(); + execAndCheckErrorListDefinition( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_BC_MTQ1_REV))), + aggregationListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_0); + + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_1_Basic_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_1_Basic_Test.java new file mode 100755 index 000000000..96fd1fcff --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_1_Basic_Test.java @@ -0,0 +1,171 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.AlertListener.MonitorAlertUpdate; +import org.ccsds.mo.mc.testbed.backends.AlertBasicDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.alert.consumer.AlertAdapter; +import org.ccsds.moims.mo.mc.structures.AlertDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.Severity; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * AL_1_Basic_Test implements the test scenario #AL-1. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AL_1_Basic_Test extends AlertTestClient { + + static AlertListener alertListener = new AlertListener(); + static Identifier subscriptionId; + + private static final AlertBasicDataset backend = new AlertBasicDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AL_1_Basic_Test.class.getName())); + setUp.setUp(null, null, backend, null, null, + false, false, true, false, false); + alertConsumerStub = setUp.getAlertConsumer(); + + // call monitorAlert.register with subscription + // subscription= + // - subscriptionId=11 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("11"); + execAndCheckMonitorAlertRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + alertListener, + System.currentTimeMillis() + TIMEOUT); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AL_1_Basic_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + alertListener.reset(); + execAndCheckMonitorAlertDeregister( + subscriptions, + alertListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call enableGeneration with enableGenParams + // enableGenParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH"} + execAndCheckEnableGeneration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT); + + // call backend.reportAlertCondition with reportCondParams + // reportCondParams= + // - alertID={"fr.cnes.mission.sat1", "MTQ1VOLTAGE_HIGH"} + // - status=true + // - arguments={{value=13.00}} + NullableAttributeList argumentValues = + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_1300))); + alertListener.reset(); + backend.reportAlertCondition( + backend.sat1Mtq1VoltageHighAdId, + true, + argumentValues); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={alertKey="MTQ1VOLTAGE_HIGH", alertVersion=1, alertSeverity=SEVERE}: + // - timestamp=?, arguments={{value=13.00}} + MonitorAlertUpdate[] targetUpdates = new MonitorAlertUpdate[1]; + targetUpdates[0] = + new MonitorAlertUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1), + UO_SEVERE, + null, // timestamp, unchecked + argumentValues); + waitAndCheckForUpdates(alertListener, startTime + TIMEOUT, targetUpdates); + + } +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_2_Generation_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_2_Generation_Test.java new file mode 100755 index 000000000..a1b964d6f --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_2_Generation_Test.java @@ -0,0 +1,434 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.AlertListener.MonitorAlertUpdate; +import org.ccsds.mo.mc.testbed.backends.AlertDefaultDataset; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mc.structures.AlertConfiguration; +import org.ccsds.moims.mo.mc.structures.AlertConfigurationList; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * AL_2_Generation_Test implements the test scenario #AL-2. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AL_2_Generation_Test extends AlertTestClient { + + static AlertListener alertListener = new AlertListener(); + static Identifier subscriptionId; + + private static final AlertDefaultDataset backend = new AlertDefaultDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AL_2_Generation_Test.class.getName())); + setUp.setUp(null, null, backend, null, null, + false, false, true, false, false); + alertConsumerStub = setUp.getAlertConsumer(); + + // call monitorAlert.register with subscription + // subscription= + // - subscriptionId=21 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("21"); + execAndCheckMonitorAlertRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + alertListener, + System.currentTimeMillis() + TIMEOUT); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AL_2_Generation_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + alertListener.reset(); + execAndCheckMonitorAlertDeregister( + subscriptions, + alertListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * Checks that Alert generation is initially disabled. + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call getAlertConfiguration with getAlertConfigParams + // getAlertConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH"} + // check response as singleton list: + // - {generationEnabled=false} + AlertConfigurationList expected = + new AlertConfigurationList(new ArrayList<>(Arrays.asList( + new AlertConfiguration(false)))); + execAndCheckGetAlertConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * Checks that no Alert is published when Alert generation is disabled. + * Requires previous execution of Test Case 1. + */ + @Test + public void testCase_02() { + // additional statement for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + + alertListener.reset(); + // call backend.reportAlertCondition with reportCondParams + // reportCondParams= + // - alertID={"fr.cnes.mission.sat1", "MTQ1VOLTAGE_HIGH"} + // - status=true + // - arguments={{value=13.05}} + NullableAttributeList argumentValues = + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_1305))); + backend.reportAlertCondition( + backend.sat1Mtq1VoltageHighAdId, + true, + argumentValues); + + // check no new message from subscription + waitAndCheckNoUpdate(alertListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * Enables Alert generation and receives an Alert. + * Requires previous execution of Test Case 2. + */ + @Test + public void testCase_03() { + // additional statement for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call enableGeneration with enableGenParams + // enableGenParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH"} + execAndCheckEnableGeneration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={alertKey="MTQ1VOLTAGE_HIGH", alertVersion=1, alertSeverity=SEVERE}: + // - timestamp=?, arguments={{value=13.05}} + MonitorAlertUpdate[] targetUpdates = new MonitorAlertUpdate[1]; + targetUpdates[0] = + new MonitorAlertUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE_HIGH, + new UInteger(1), + UO_SEVERE, + null, // timestamp, unchecked + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_1305)))); + waitAndCheckForUpdates(alertListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 4. + * Checks the null keys option. + * Requires previous execution of Test Case 3. + */ + @Test + public void testCase_04() { + // additional statement for dependent tests + TestDependency.before(3, this, "testCase_03", 4); + + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call enableGeneration with enableGenParams + // enableGenParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + execAndCheckEnableGeneration( + Constant.DOMAIN_SAT1, + null, + alertListener, + startTime + TIMEOUT); + + // check no new message from subscription + waitAndCheckNoUpdate(alertListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // call backend.reportAlertCondition with reportCondParams1 + // reportCondParams1= + // - alertID={"fr.cnes.mission.sat1", "MTQ1VOLTAGE_HIGH"} + // - status=false + // - arguments={{value=9.10}} + NullableAttributeList argumentValues = + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_910))); + alertListener.reset(); + backend.reportAlertCondition( + backend.sat1Mtq1VoltageHighAdId, + false, + argumentValues); + + // call backend.reportAlertCondition with reportCondParams2 + // reportCondParams2= + // - alertID={"fr.cnes.mission.sat1", "MTQ1VOLTAGE_LOW"} + // - status=true + // - arguments={{value=9.10}} + alertListener.reset(); + backend.reportAlertCondition( + backend.sat1Mtq1VoltageLowAdId, + true, + argumentValues); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={alertKey="MTQ1VOLTAGE_LOW", alertVersion=1, alertSeverity=SEVERE}: + // - timestamp=?, arguments={{value=9.10}} + MonitorAlertUpdate[] targetUpdates = new MonitorAlertUpdate[1]; + targetUpdates[0] = + new MonitorAlertUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE_LOW, + new UInteger(1), + UO_SEVERE, + null, // timestamp, unchecked + argumentValues); + waitAndCheckForUpdates(alertListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 5. + * Disables Alert generation and receives no Alert. + * Requires previous execution of Test Case 4. + */ + @Test + public void testCase_05() { + // additional statement for dependent tests + TestDependency.before(4, this, "testCase_04", 5); + + System.out.println("Running: testCase_05()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call disableGeneration with disableGenParams + // disableGenParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH"} + execAndCheckDisableGeneration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT); + + // call backend.reportAlertCondition with reportCondParams1 + // reportCondParams1= + // - alertID={"fr.cnes.mission.sat1", "MTQ1VOLTAGE_HIGH"} + // - status=true + // - arguments={{value=13.15}} + NullableAttributeList argumentValues = + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_1315))); + alertListener.reset(); + backend.reportAlertCondition( + backend.sat1Mtq1VoltageHighAdId, + true, + argumentValues); + + // call backend.reportAlertCondition with reportCondParams2 + // reportCondParams2= + // - alertID={"fr.cnes.mission.sat1", "MTQ1VOLTAGE_LOW"} + // - status=false + // - arguments={{value=13.15}} + alertListener.reset(); + backend.reportAlertCondition( + backend.sat1Mtq1VoltageLowAdId, + false, + argumentValues); + + // check no new message from subscription + waitAndCheckNoUpdate(alertListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 6. + * Checks the null keys option. + * Requires previous execution of Test Case 5. + */ + @Test + public void testCase_06() { + // additional statement for dependent tests + TestDependency.before(5, this, "testCase_05", 6); + + System.out.println("Running: testCase_06()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call disableGeneration with disableGenParams + // disableGenParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH"} + execAndCheckDisableGeneration( + Constant.DOMAIN_SAT1, + null, + alertListener, + startTime + TIMEOUT); + + // call backend.reportAlertCondition with reportCondParams1 + // reportCondParams1= + // - alertID={"fr.cnes.mission.sat1", "MTQ1VOLTAGE_HIGH"} + // - status=false + // - arguments={{value=9.20}} + NullableAttributeList argumentValues = + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_920))); + alertListener.reset(); + backend.reportAlertCondition( + backend.sat1Mtq1VoltageHighAdId, + false, + argumentValues); + + // call backend.reportAlertCondition with reportCondParams2 + // reportCondParams2= + // - alertID={"fr.cnes.mission.sat1", "MTQ1VOLTAGE_LOW"} + // - status=true + // - arguments={{value=9.20}} + alertListener.reset(); + backend.reportAlertCondition( + backend.sat1Mtq1VoltageLowAdId, + true, + argumentValues); + + // check no new message from subscription + waitAndCheckNoUpdate(alertListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 7. + * Checks getAlertConfiguration with a null domain. + * Requires previous execution of Test Case 6. + */ + @Test + public void testCase_07() { + // additional statement for dependent tests + TestDependency.before(6, this, "testCase_06", 7); + + System.out.println("Running: testCase_07()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call getAlertConfiguration with getAlertConfigParams + // getAlertConfigParams= + // - domain=null + // - keys={"MTQ1VOLTAGE_HIGH"} + // check response as singleton list: + // - {generationEnabled=false} + AlertConfigurationList expected = + new AlertConfigurationList(new ArrayList<>(Arrays.asList( + new AlertConfiguration(false)))); + execAndCheckGetAlertConfiguration( + null, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_9_Errors_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_9_Errors_Test.java new file mode 100755 index 000000000..0f1e96bac --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AL_9_Errors_Test.java @@ -0,0 +1,236 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.backends.AlertErrorDataset; +import org.ccsds.moims.mo.mal.MALHelper; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mc.MCHelper; +import org.ccsds.moims.mo.mc.structures.AlertConfiguration; +import org.ccsds.moims.mo.mc.structures.AlertConfigurationList; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * AL_9_Errors_Test implements the test scenario #AL-9. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AL_9_Errors_Test extends AlertTestClient { + + static AlertListener alertListener = new AlertListener(); + static Identifier subscriptionId; + + private static final AlertErrorDataset backend = new AlertErrorDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(AL_9_Errors_Test.class.getName())); + setUp.setUp(null, null, backend, null, null, + false, false, true, false, false); + alertConsumerStub = setUp.getAlertConsumer(); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + AL_9_Errors_Test.class.getName() + " tearDownClass()"); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test ambiguity with a null domain + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call getAlertConfiguration with getAlertConfigParams + // getAlertConfigParams= + // - domain=null + // - keys={"MTQ1VOLTAGE_HIGH"} + // check ERROR message with code Ambiguous + // check the extraInfo field as a singleton list holding element 0 + execAndCheckErrorGetAlertConfiguration( + null, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT, + MCHelper.AMBIGUOUS_ERROR_NUMBER, + new UIntegerList(new ArrayList<>(Arrays.asList( + new UInteger(0))))); + + } + + /** + * Test Case 2. + * test unknown alert + */ + @Test + public void testCase_02() { + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call getAlertConfiguration with getAlertConfigParams + // getAlertConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_LOW", "MTQ1VOLTAGE_HIGH"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 0 + execAndCheckErrorGetAlertConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_LOW, + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + new UIntegerList(new ArrayList<>(Arrays.asList( + new UInteger(0))))); + + } + + /** + * Test Case 3. + * test atomicity of enableGeneration operation + */ + @Test + public void testCase_03() { + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call enableGeneration with enableGenParams + // enableGenParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH", "MTQ1VOLTAGE_LOW"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 1 + execAndCheckErrorEnableGeneration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH, + Constant.ID_MTQ1VOLTAGE_LOW))), + alertListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + new UIntegerList(new ArrayList<>(Arrays.asList( + new UInteger(1))))); + + alertListener.reset(); + // call getAlertConfiguration with getAlertConfigParams + // getAlertConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH"} + // check response as singleton list: + // - {generationEnabled=false} + execAndCheckGetAlertConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT, + new AlertConfigurationList(new ArrayList<>(Arrays.asList( + new AlertConfiguration(false))))); + + } + + /** + * Test Case 4. + * test atomicity of disableGeneration operation + */ + @Test + public void testCase_04() { + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + alertListener.reset(); + // call enableGeneration with enableGenParams + // enableGenParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH"} + // check ACK message + execAndCheckEnableGeneration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT); + + alertListener.reset(); + // call disableGeneration with disableGenParams + // disableGenParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH", "MTQ1VOLTAGE_LOW"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 1 + execAndCheckErrorDisableGeneration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH, + Constant.ID_MTQ1VOLTAGE_LOW))), + alertListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + new UIntegerList(new ArrayList<>(Arrays.asList( + new UInteger(1))))); + + alertListener.reset(); + // call getAlertConfiguration with getAlertConfigParams + // getAlertConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"MTQ1VOLTAGE_HIGH"} + // check response as singleton list: + // - {generationEnabled=true} + execAndCheckGetAlertConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE_HIGH))), + alertListener, + startTime + TIMEOUT, + new AlertConfigurationList(new ArrayList<>(Arrays.asList( + new AlertConfiguration(true))))); + + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ActionListener.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ActionListener.java new file mode 100755 index 000000000..ac6a767ff --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ActionListener.java @@ -0,0 +1,235 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UOctet; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.action.consumer.ActionAdapter; +import org.ccsds.moims.mo.mc.structures.ActionCategory; +import org.ccsds.moims.mo.mc.structures.ActionEvent; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; + +public class ActionListener extends ActionAdapter { + + static class MonitorExecutionUpdate { + IdentifierList domain; + Long requestId; + Identifier actionKey; + ActionCategory actionCategory; + ActionEvent progressEvent; + public MonitorExecutionUpdate( + IdentifierList domain, + Long requestId, + Identifier actionKey, + ActionCategory actionCategory, + ActionEvent progressEvent) { + this.domain = domain; + this.requestId = requestId; + this.actionKey = actionKey; + this.actionCategory = actionCategory; + this.progressEvent = progressEvent; + } + public String toString() { + StringBuilder out = new StringBuilder(); + out.append(this.getClass().getName()); + out.append("{domain=").append(domain); + out.append(", requestId=").append(requestId); + out.append(", actionKey=").append(actionKey); + out.append(", actionCategory=").append(actionCategory); + out.append(", progressEvent=").append(progressEvent); + out.append("}"); + return out.toString(); + } + } + + String testException = null; + MOErrorException error = null; + boolean executeAckReceived = false; + boolean registerAckReceived = false; + boolean deregisterAckReceived = false; + ConcurrentLinkedQueue executionUpdates = new ConcurrentLinkedQueue<>(); + + synchronized void reset() { + testException = null; + error = null; + executeAckReceived = false; + registerAckReceived = false; + deregisterAckReceived = false; + executionUpdates.clear(); + } + + public String toString() { + StringBuilder out = new StringBuilder(); + String prefix=""; + out.append(this.getClass().getName()); + if (testException != null) { + out.append(prefix).append("testException=").append(testException); + prefix = ", "; + } + if (error != null) { + out.append(prefix).append("error=").append(error); + prefix = ", "; + } + if (executeAckReceived) { + out.append(prefix).append("executeAckReceived=").append(executeAckReceived); + prefix = ", "; + } + if (registerAckReceived) { + out.append(prefix).append("registerAckReceived=").append(registerAckReceived); + prefix = ", "; + } + if (deregisterAckReceived) { + out.append(prefix).append("deregisterAckReceived=").append(deregisterAckReceived); + prefix = ", "; + } + if (executionUpdates != null) { + out.append(prefix).append("executionUpdates=").append(executionUpdates); + prefix = ", "; + } + out.append("}"); + return out.toString(); + } + + public boolean hasError() { + return testException != null || error != null; + } + public String getError() { + if (error != null) + return error.toString(); + return testException; + } + + private void addTestException(String testException) { + if (this.testException == null) + this.testException = testException; + } + + @Override + public void executeAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: executeAckReceived()"); + synchronized(this) { + executeAckReceived = true; + notify(); + } + } + @Override + public void executeErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: executeErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void monitorExecutionRegisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: monitorExecutionRegisterAckReceived()"); + synchronized(this) { + registerAckReceived = true; + notify(); + } + } + @Override + public void monitorExecutionRegisterErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: monitorExecutionRegisterErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void monitorExecutionNotifyReceived( + MALMessageHeader msgHeader, + Identifier subscriptionId, + UpdateHeader updateHeader, + ActionEvent progressEvent, + Map qosProperties) { + System.out.println("Reached: monitorExecutionNotifyReceived() -> " + progressEvent); + // all subscription keys are used in all the tests + NullableAttributeList keyValues = updateHeader.getKeyValues(); + Long requestId = null; + Identifier actionKey = null; + ActionCategory actionCategory = null; + if (keyValues == null || keyValues.size() != 3) { + addTestException("Unexpected number of subscription key values"); + } else { + Attribute key = keyValues.get(0).getValue(); + if (key != null) + requestId = ((Union) key).getLongValue(); + key = keyValues.get(1).getValue(); + if (key != null) + actionKey = (Identifier) key; + key = keyValues.get(2).getValue(); + if (key != null) + actionCategory = new ActionCategory(((UOctet) key).getValue()); + } + synchronized(this) { + executionUpdates.add(new MonitorExecutionUpdate( + updateHeader.getDomain(), + requestId, + actionKey, + actionCategory, + progressEvent)); + notify(); + } + } + @Override + public void monitorExecutionNotifyErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: monitorExecutionNotifyErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void monitorExecutionDeregisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: monitorExecutionDeregisterAckReceived()"); + synchronized(this) { + deregisterAckReceived = true; + notify(); + } + } +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ActionTestClient.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ActionTestClient.java new file mode 100755 index 000000000..fece8e32d --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ActionTestClient.java @@ -0,0 +1,297 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; + +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALHelper; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mal.structures.ULong; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mc.structures.ActionExecutionRequest; + +/** + * This class provides shared functions for all Action test clients. + */ +public class ActionTestClient extends MCTest { + + // test values used in Action tests for MIS_TC_DEFATTITUDE args + public static final NullableAttribute NA_DOUBLE_13E0 = new NullableAttribute(new Union(new Double(1.3e0))); + public static final NullableAttribute NA_DOUBLE_21E9 = new NullableAttribute(new Union(new Double(2.1e9))); + public static final NullableAttribute NA_DOUBLE_60E1 = new NullableAttribute(new Union(new Double(6.0e1))); + public static final NullableAttribute NA_STRING_OK = new NullableAttribute(new Union(Constant.STR_OK)); + public static final NullableAttribute NA_STRING_FAIL2 = new NullableAttribute(new Union(Constant.STR_FAIL2)); + public static final NullableAttribute NA_STRING_SKIP = new NullableAttribute(new Union(Constant.STR_SKIP)); + public static final NullableAttribute NA_STRING_WAIT = new NullableAttribute(new Union(Constant.STR_WAIT)); + public static final NullableAttribute NA_STRING_ERROR_REJECTED = + new NullableAttribute(new Union(new String("error Rejected"))); + public static final NullableAttribute NA_ULONG_0 = new NullableAttribute(new ULong(new java.math.BigInteger("0"))); + public static final NullableAttribute NA_NULL = new NullableAttribute(null); + + public static final NullableAttribute NA_TIME_10000 = + new NullableAttribute(new Time(10000)); + public static final NullableAttributeList CHGTABSVAL_DFLT_ARGS = + new NullableAttributeList(new ArrayList<> (Arrays.asList(NA_TIME_10000))); + public static final NullableAttributeList DEFATTITUDE_DFLT_ARGS = + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_21E9, NA_DOUBLE_60E1, NA_STRING_OK, NA_ULONG_0, + NA_DOUBLE_13E0, NA_NULL, NA_NULL))); + + protected static void execAndCheckMonitorExecutionRegister( + Subscription subscription, + ActionListener listener, + long maxTime) { + + try { + long startTime = System.currentTimeMillis(); + long timeout = maxTime - startTime; + actionConsumerStub = setUp.getActionConsumer(); + actionConsumerStub.asyncMonitorExecutionRegister( + subscription, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.registerAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timeout + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.registerAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckMonitorExecutionDeregister( + IdentifierList subscriptions, + ActionListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + actionConsumerStub.asyncMonitorExecutionDeregister( + subscriptions, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.deregisterAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate it + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.deregisterAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void waitAndCheckForUpdates( + ActionListener listener, + long maxTime, + ActionListener.MonitorExecutionUpdate[] updates) { + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + int nbUpdates = updates.length; + synchronized(listener) { + while (!listener.hasError() && + listener.executionUpdates.size() != nbUpdates && + timeout > 0) { + try { + System.out.println("wait for Updates from subscription"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + System.out.println("end wait, listener=" + listener); + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.executionUpdates.size() != nbUpdates) + unitTestFail("Incorrect number of updates received: " + + "expected " + nbUpdates + + " was " + listener.executionUpdates.size()); + // check received updates + Iterator it = listener.executionUpdates.iterator(); + for (int idx = 0; it.hasNext(); idx++) { + assertEquals("Update[" + idx + "]", updates[idx], it.next()); + } + } + } + + protected static void execAndCheckExecute( + ActionExecutionRequest request, + ActionListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + actionConsumerStub.asyncExecute( + request, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.executeAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timeout + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.executeAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckErrorExecute( + ActionExecutionRequest request, + ActionListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + actionConsumerStub.asyncExecute( + request, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.executeAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timeout + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.executeAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + + protected static void assertEquals( + String error, + ActionListener.MonitorExecutionUpdate expected, + ActionListener.MonitorExecutionUpdate actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + ", expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + ", expecting " + expected + ", was " + actual); + if (!actual.domain.equals(expected.domain)) + unitTestFail(error + " unexpected domain" + + ", expecting " + expected.domain + + ", was " + actual.domain); + if (!actual.requestId.equals(expected.requestId)) + unitTestFail(error + " unexpected requestId subscription key" + + ", expecting " + expected.requestId + + ", was " + actual.requestId); + if (!actual.actionKey.equals(expected.actionKey)) + unitTestFail(error + " unexpected actionKey subscription key" + + ", expecting " + expected.actionKey + + ", was " + actual.actionKey); + if (!actual.actionCategory.equals(expected.actionCategory)) + unitTestFail(error + " unexpected actionCategory subscription key" + + ", expecting " + expected.actionCategory + + ", was " + actual.actionCategory); + assertEquals(error + " progressEvent", expected.progressEvent, actual.progressEvent); + } + +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AggregationListener.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AggregationListener.java new file mode 100755 index 000000000..b8503debe --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AggregationListener.java @@ -0,0 +1,438 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.aggregation.consumer.AggregationAdapter; +import org.ccsds.moims.mo.mc.structures.AggregationDefinitionList; +import org.ccsds.moims.mo.mc.structures.AggregationValueList; +import org.ccsds.moims.mo.mc.structures.ParameterValueDataList; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; + +public class AggregationListener extends AggregationAdapter { + + static class MonitorValueUpdate { + IdentifierList domain; + Identifier aggregationKey; + UInteger aggregationVersion; + Time timestamp; + ParameterValueDataList values; + public MonitorValueUpdate( + IdentifierList domain, + Identifier aggregationKey, + UInteger aggregationVersion, + Time timestamp, + ParameterValueDataList values) { + this.domain = domain; + this.aggregationKey = aggregationKey; + this.aggregationVersion = aggregationVersion; + this.timestamp = timestamp; + this.values = values; + } + public String toString() { + StringBuilder out = new StringBuilder(); + out.append(this.getClass().getName()); + out.append("{domain=").append(domain); + out.append(", aggregationKey=").append(aggregationKey); + out.append(", aggregationVersion=").append(aggregationVersion); + out.append(", timestamp=").append(timestamp); + out.append(", values=").append(values); + out.append("}"); + return out.toString(); + } + } + + String testException = null; + MOErrorException error = null; + boolean registerAckReceived = false; + boolean deregisterAckReceived = false; + AggregationValueList getValueResponse = null; + ConcurrentLinkedQueue valueUpdates = new ConcurrentLinkedQueue<>(); + ReportConfigurationList getReportConfigResponse = null; + boolean enableReportingAckReceived = false; + boolean disableReportingAckReceived = false; + boolean setReportingPeriodAckReceived = false; + AggregationDefinitionList listDefinitionResponse = null; + boolean addAggregationAckReceived = false; + boolean removeAggregationAckReceived = false; + + synchronized void reset() { + testException = null; + error = null; + registerAckReceived = false; + deregisterAckReceived = false; + getValueResponse = null; + valueUpdates.clear(); + getReportConfigResponse = null; + enableReportingAckReceived = false; + disableReportingAckReceived = false; + setReportingPeriodAckReceived = false; + listDefinitionResponse = null; + addAggregationAckReceived = false; + removeAggregationAckReceived = false; + } + + public String toString() { + StringBuilder out = new StringBuilder(); + String prefix=""; + out.append(this.getClass().getName()); + if (testException != null) { + out.append(prefix).append("testException=").append(testException); + prefix = ", "; + } + if (error != null) { + out.append(prefix).append("error=").append(error); + prefix = ", "; + } + if (registerAckReceived) { + out.append(prefix).append("registerAckReceived=").append(registerAckReceived); + prefix = ", "; + } + if (deregisterAckReceived) { + out.append(prefix).append("deregisterAckReceived=").append(deregisterAckReceived); + prefix = ", "; + } + if (getValueResponse != null) { + out.append(prefix).append("getValueResponse=").append(getValueResponse); + prefix = ", "; + } + if (valueUpdates != null) { + out.append(prefix).append("valueUpdates=").append(valueUpdates); + prefix = ", "; + } + if (getReportConfigResponse != null) { + out.append(prefix).append("getReportConfigResponse=").append(getReportConfigResponse); + prefix = ", "; + } + if (enableReportingAckReceived) { + out.append(prefix).append("enableReportingAckReceived=").append(enableReportingAckReceived); + prefix = ", "; + } + if (disableReportingAckReceived) { + out.append(prefix).append("disableReportingAckReceived=").append(disableReportingAckReceived); + prefix = ", "; + } + if (setReportingPeriodAckReceived) { + out.append(prefix).append("setReportingPeriodAckReceived=").append(setReportingPeriodAckReceived); + prefix = ", "; + } + if (listDefinitionResponse != null) { + out.append(prefix).append("listDefinitionResponse=").append(listDefinitionResponse); + prefix = ", "; + } + if (addAggregationAckReceived) { + out.append(prefix).append("addAggregationAckReceived=").append(addAggregationAckReceived); + prefix = ", "; + } + if (removeAggregationAckReceived) { + out.append(prefix).append("removeAggregationAckReceived=").append(removeAggregationAckReceived); + prefix = ", "; + } + out.append("}"); + return out.toString(); + } + + public boolean hasError() { + return testException != null || error != null; + } + public String getError() { + if (error != null) + return error.toString(); + return testException; + } + + private void addTestException(String testException) { + if (this.testException == null) + this.testException = testException; + } + + @Override + public void getValueResponseReceived( + MALMessageHeader msgHeader, + AggregationValueList values, + Map qosProperties) { + System.out.println("Reached: getValueResponseReceived()"); + if (values == null) { + // OUT field is not nullable + addTestException("getValueResponse OUT parameter is null"); + } + synchronized(this) { + this.getValueResponse = values; + notify(); + } + } + @Override + public void getValueErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: getValueErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void monitorValueRegisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: monitorValueRegisterAckReceived()"); + synchronized(this) { + registerAckReceived = true; + notify(); + } + } + @Override + public void monitorValueRegisterErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: monitorValueRegisterErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void monitorValueNotifyReceived( + MALMessageHeader msgHeader, + Identifier subscriptionId, + UpdateHeader updateHeader, + Time timestamp, + ParameterValueDataList values, + Map qosProperties) { + System.out.println("Reached: monitorValueNotifyReceived() -> " + timestamp + " " + values); + // all subscription keys are used in all the tests + NullableAttributeList keyValues = updateHeader.getKeyValues(); + Identifier aggregationKey = null; + UInteger aggregationVersion = null; + if (keyValues == null || keyValues.size() != 2) { + addTestException("Unexpected number of subscription key values"); + } else { + Attribute aKey = keyValues.get(0).getValue(); + if (aKey != null) + aggregationKey = (Identifier) aKey; + Attribute aVersion = keyValues.get(1).getValue(); + if (aVersion != null) + aggregationVersion = (UInteger) aVersion; + } + synchronized(this) { + valueUpdates.add(new MonitorValueUpdate( + updateHeader.getDomain(), + aggregationKey, aggregationVersion, + timestamp, values)); + notify(); + } + } + @Override + public void monitorValueNotifyErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: monitorValueNotifyErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void monitorValueDeregisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: monitorValueDeregisterAckReceived()"); + synchronized(this) { + deregisterAckReceived = true; + notify(); + } + } + + @Override + public void getReportingConfigurationResponseReceived( + MALMessageHeader msgHeader, + ReportConfigurationList reportConfigs, + Map qosProperties) { + System.out.println("Reached: getReportingConfigurationResponseReceived()"); + if (reportConfigs == null) { + // OUT field is not nullable + addTestException("getReportingConfiguration OUT parameter is null"); + } + synchronized(this) { + this.getReportConfigResponse = reportConfigs; + notify(); + } + } + @Override + public void getReportingConfigurationErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: getReportingConfigurationErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void enableReportingAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: enableReportingAckReceived()"); + synchronized(this) { + enableReportingAckReceived = true; + notify(); + } + } + @Override + public void enableReportingErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: enableReportingErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void disableReportingAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: disableReportingAckReceived()"); + synchronized(this) { + disableReportingAckReceived = true; + notify(); + } + } + @Override + public void disableReportingErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: disableReportingErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void setReportingPeriodAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: setReportingPeriodAckReceived()"); + synchronized(this) { + setReportingPeriodAckReceived = true; + notify(); + } + } + @Override + public void setReportingPeriodErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: setReportingPeriodErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void listDefinitionResponseReceived( + MALMessageHeader msgHeader, + AggregationDefinitionList definitions, + Map qosProperties) { + System.out.println("Reached: listDefinitionResponseReceived()"); + synchronized(this) { + this.listDefinitionResponse = definitions; + notify(); + } + } + @Override + public void listDefinitionErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: listDefinitionErrorReceived(): " + error); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void addAggregationAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: addAggregationAckReceived()"); + synchronized(this) { + addAggregationAckReceived = true; + notify(); + } + } + @Override + public void addAggregationErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: addAggregationErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void removeAggregationAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: removeAggregationAckReceived()"); + synchronized(this) { + removeAggregationAckReceived = true; + notify(); + } + } + @Override + public void removeAggregationErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: removeAggregationErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AggregationTestClient.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AggregationTestClient.java new file mode 100755 index 000000000..1a666d035 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AggregationTestClient.java @@ -0,0 +1,1179 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import org.ccsds.mo.mc.testbed.AggregationListener.MonitorValueUpdate; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.ObjectRefList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mc.structures.AggregationDefinition; +import org.ccsds.moims.mo.mc.structures.AggregationDefinitionList; +import org.ccsds.moims.mo.mc.structures.AggregationValue; +import org.ccsds.moims.mo.mc.structures.AggregationValueList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; +import org.ccsds.moims.mo.mc.structures.ValidityState; + +/** +* This class provides shared functions for all Aggregation test clients. +*/ +public class AggregationTestClient extends MCTest { + + public static final Duration DURATION__1 = new Duration(-1); + public static final Duration DURATION_0 = new Duration(0); + public static final Duration DURATION_60 = new Duration(60); + public static final Duration DURATION_120 = new Duration(120); + public static final Duration DURATION_301 = new Duration(301); + public static final Duration DURATION_602 = new Duration(602); + + public static final ParameterValueData INVALID_RAW_VALUE = + new ParameterValueData( + ValidityState.INVALID_RAW, + null, + null); + public static final ParameterValueData MTQ1ENABLED_ENABLED_VALUE = + new ParameterValueData( + ValidityState.VALID, + NA_UINT_1.getValue(), + NA_STRING_ENABLED.getValue()); + public static final ParameterValueData MTQ1ENABLED_EXPIRED_VALUE = + new ParameterValueData( + ValidityState.EXPIRED, + NA_UINT_1.getValue(), + NA_STRING_ENABLED.getValue()); + + public static final ParameterValueData MTQ1VOLTAGE_1200_VALUE = + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_1200.getValue(), + null); + public static final ParameterValueData MTQ1VOLTAGE_2200_VALUE = + new ParameterValueData(ValidityState.VALID, + NA_DOUBLE_2200.getValue(), + null); + + public static ObjectIdentity getAggregationIdentity( + ObjectRef objectRef) { + if (objectRef == null) + return null; + return new ObjectIdentity( + objectRef.getDomain(), + objectRef.getKey(), + objectRef.getObjectVersion()); + } + + protected static void execAndCheckMonitorValueRegister( + Subscription subscription, + AggregationListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncMonitorValueRegister( + subscription, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.registerAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate it + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.registerAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckMonitorValueDeregister( + IdentifierList subscriptions, + AggregationListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncMonitorValueDeregister( + subscriptions, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.deregisterAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate it + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.deregisterAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + /** + * Waits for expected updates and checks them. + * + * @param listener callback listener + * @param maxTime max waiting time + * @param updates expected updates + */ + protected static void waitAndCheckForUpdates( + AggregationListener listener, + long maxTime, + MonitorValueUpdate[] updates) { + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + int nbUpdates = updates.length; + synchronized(listener) { + while (!listener.hasError() && + listener.valueUpdates.size() != nbUpdates && + timeout > 0) { + try { + System.out.println("wait for Updates from subscription"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + System.out.println("end wait, listener=" + listener); + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.valueUpdates.size() != nbUpdates) + unitTestFail("Incorrect number of updates received: " + + "expected " + nbUpdates + + " was " + listener.valueUpdates.size()); + // check received updates + Iterator it = listener.valueUpdates.iterator(); + for (int idx = 0; it.hasNext(); idx++) { + assertEquals("Update[" + idx + "]", updates[idx], it.next()); + } + } + } + + /** + * Waits for expected updates and checks them. + * + * @param listener callback listener + * @param maxTime max waiting time + * @param updatesTab list of expected updates, grouped by Aggregation + */ + protected static void waitAndCheckForUpdates( + AggregationListener listener, + long maxTime, + MonitorValueUpdate[][] updatesTab) { + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + int nbUpdates = 0; + for (int i=0; i 0) { + try { + System.out.println("wait for Updates from subscription"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + System.out.println("end wait, listener=" + listener); + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.valueUpdates.size() != nbUpdates) + unitTestFail("Incorrect number of updates received: " + + "expected " + nbUpdates + + " was " + listener.valueUpdates.size()); + // check received updates + Hashtable, List> received = + new Hashtable<>(updatesTab.length); + for (int i=0; i( + updatesTab[i][0].domain, + AggregationDefinition.TYPE_ID.getTypeId(), + updatesTab[i][0].aggregationKey, + updatesTab[i][0].aggregationVersion), + new ArrayList(updatesTab[i].length)); + Iterator it = listener.valueUpdates.iterator(); + while (it.hasNext()) { + MonitorValueUpdate update = it.next(); + List updates = received.get( + new ObjectRef<>( + update.domain, + AggregationDefinition.TYPE_ID.getTypeId(), + update.aggregationKey, + update.aggregationVersion)); + updates.add(update); + } + for (int i=0; i aggregation = new ObjectRef<>( + updatesTab[i][0].domain, + AggregationDefinition.TYPE_ID.getTypeId(), + updatesTab[i][0].aggregationKey, + updatesTab[i][0].aggregationVersion); + List updates = received.get(aggregation); + if (updates.size() != updatesTab[i].length) + unitTestFail("Incorrect number of updates received for Aggregation " + aggregation + ": " + + "expected " + updatesTab[i].length + + " was " + updates.size()); + it = updates.iterator(); + for (int idx = 0; it.hasNext(); idx++) { + assertEquals( + "Update[" + idx + "] for Aggregation " + aggregation, + updatesTab[i][idx], it.next()); + } + } + } + } + + protected static void waitAndCheckNoUpdate( + AggregationListener listener, + long maxTime) { + // ------------------------------------------------------------------------ + // Wait for TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + synchronized(listener) { + while (!listener.hasError() && + timeout > 0) { + try { + System.out.println("wait for timeout"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + + // check no new message from subscription + if (!listener.valueUpdates.isEmpty()) + unitTestFail("received unexpected updates"); + } + } + + protected static void execAndCheckGetValue( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime, + AggregationValueList expected) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncGetValue( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for response or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.getValueResponse == null && + timeout > 0) { + try { + System.out.println("wait for response"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.getValueResponse == null) + unitTestFail("The RESPONSE was not received!"); + + assertEquals("error in getValue RESPONSE", expected, listener.getValueResponse); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorGetValue( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncGetValue( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.getValueResponse == null && + timeout > 0) { + try { + System.out.println("wait for response"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.getValueResponse != null) + unitTestFail("Unexpected RESPONSE received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckGetReportingConfiguration( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime, + ReportConfigurationList expected) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncGetReportingConfiguration( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for response or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.getReportConfigResponse == null && + timeout > 0) { + try { + System.out.println("wait for response"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.getReportConfigResponse == null) + unitTestFail("The RESPONSE was not received!"); + + ParameterTestClient.assertEquals( + "error in getReportingConfiguration RESPONSE", + expected, + listener.getReportConfigResponse); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckEnableReporting( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncEnableReporting( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.enableReportingAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.enableReportingAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorEnableReporting( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncEnableReporting( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.enableReportingAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.enableReportingAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckDisableReporting( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncDisableReporting( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.disableReportingAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.disableReportingAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorDisableReporting( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncDisableReporting( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.disableReportingAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.disableReportingAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckSetReportingPeriod( + IdentifierList domain, + IdentifierList keys, + Duration reportInterval, + AggregationListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncSetReportingPeriod( + domain, + keys, + reportInterval, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.setReportingPeriodAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.setReportingPeriodAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorSetReportingPeriod( + IdentifierList domain, + IdentifierList keys, + Duration reportInterval, + AggregationListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncSetReportingPeriod( + domain, + keys, + reportInterval, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.setReportingPeriodAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.setReportingPeriodAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckListDefinition( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime, + AggregationDefinitionList expected) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncListDefinition( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for RESPONSE or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.listDefinitionResponse == null && + timeout > 0) { + try { + System.out.println("wait for RESPONSE"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.listDefinitionResponse == null) + unitTestFail("The RESPONSE was not received!"); + + if (keys == null) { + assertMatches( + "error in listDefinition RESPONSE", + expected, + listener.listDefinitionResponse); + } else { + assertEquals( + "error in listDefinition RESPONSE", + expected, + listener.listDefinitionResponse); + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorListDefinition( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncListDefinition( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for RESPONSE or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.listDefinitionResponse == null && + timeout > 0) { + try { + System.out.println("wait for RESPONSE"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.listDefinitionResponse != null) + unitTestFail("Unexpected RESPONSE received"); + if (listener.error == null) + unitTestFail("Missing expected RESPONSE error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckAddAggregation( + AggregationDefinitionList newObjects, + AggregationListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncAddAggregation( + newObjects, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.addAggregationAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.addAggregationAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorAddAggregation( + AggregationDefinitionList newObjects, + AggregationListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncAddAggregation( + newObjects, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.addAggregationAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.addAggregationAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckRemoveAggregation( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncRemoveAggregation( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.removeAggregationAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.removeAggregationAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorRemoveAggregation( + IdentifierList domain, + IdentifierList keys, + AggregationListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + aggregationConsumerStub.asyncRemoveAggregation( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.removeAggregationAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.removeAggregationAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void assertEquals( + String error, + MonitorValueUpdate expected, + MonitorValueUpdate actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + ", expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + ", expecting " + expected + ", was " + actual); + if (!expected.domain.equals(actual.domain)) + unitTestFail(error + " unexpected domain" + + ", expecting " + expected.domain + + ", was " + actual.domain); + if (!expected.aggregationKey.equals(actual.aggregationKey)) + unitTestFail(error + " unexpected aggregationKey subscription key" + + ", expecting " + expected.aggregationKey + + ", was " + actual.aggregationKey); + if (!expected.aggregationVersion.equals(actual.aggregationVersion)) + unitTestFail(error + " unexpected aggregationVersion subscription key" + + ", expecting " + expected.aggregationVersion + + ", was " + actual.aggregationVersion); + ParameterTestClient.assertEquals(error + " values", expected.values, actual.values); + } + + public static void assertEquals(String error, AggregationValueList expected, AggregationValueList actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); + } + } + public static void assertEquals(String error, AggregationValue expected, AggregationValue actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected value, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); + assertEquals(error + " aggregationRef", expected.getAggregationRef(), actual.getAggregationRef()); + // ignore timestamp + ParameterTestClient.assertEquals(error + " value", expected.getParameterValues(), actual.getParameterValues()); + } + + public static void assertEquals(String error, AggregationDefinitionList expected, AggregationDefinitionList actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); + } + } + public static void assertEquals(String error, AggregationDefinition expected, AggregationDefinition actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected value, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); + if (! expected.getObjectIdentity().equals(actual.getObjectIdentity())) + unitTestFail(error + " unexpected objectIdentity" + + ", expecting " + expected.getObjectIdentity() + + ", was " + actual.getObjectIdentity()); + if (! expected.getDescription().equals(actual.getDescription())) + unitTestFail(error + " unexpected description" + + ", expecting " + expected.getDescription() + + ", was " + actual.getDescription()); + if ((expected.getCategory() == null && actual.getCategory() != null) || + (expected.getCategory() != null && !expected.getCategory().equals(actual.getCategory()))) + unitTestFail(error + " unexpected category" + + ", expecting " + expected.getCategory() + + ", was " + actual.getCategory()); + assertEquals(error + " parameters", expected.getParameters(), actual.getParameters()); + } + public static void assertMatches(String error, AggregationDefinitionList expected, AggregationDefinitionList actual) { + // order of elements is not relevant + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + HashMap actualMap = new HashMap<>(); + for (int i = 0; i < actual.size(); i++) { + if (actualMap.put(actual.get(i).getObjectIdentity(), actual.get(i)) != null) + unitTestFail(error + " duplicate element " + i + ": " + actual.get(i)); + } + for (int i = 0; i < expected.size(); i++) { + ObjectIdentity aggregId = expected.get(i).getObjectIdentity(); + AggregationDefinition actualDefinition = actualMap.get(aggregId); + assertEquals(error + " [" + i + "]", expected.get(i), actualDefinition); + actualMap.remove(aggregId); + } + } + + public static void assertEquals(String error, ObjectRefList expected, ObjectRefList actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); + } + } + public static void assertEquals(String error, ObjectRef expected, ObjectRef actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected value, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); + if (! expected.getTypeId().equals(actual.getTypeId())) + unitTestFail(error + " unexpected typeId" + + ", expecting " + expected.getTypeId() + + ", was " + actual.getTypeId()); + if (! expected.getDomain().equals(actual.getDomain())) + unitTestFail(error + " unexpected domain" + + ", expecting " + expected.getDomain() + + ", was " + actual.getDomain()); + if (! expected.getKey().equals(actual.getKey())) + unitTestFail(error + " unexpected key" + + ", expecting " + expected.getKey() + + ", was " + actual.getKey()); + if (! expected.getObjectVersion().equals(actual.getObjectVersion())) + unitTestFail(error + " unexpected objectVersion" + + ", expecting " + expected.getObjectVersion() + + ", was " + actual.getObjectVersion()); + } + +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AlertListener.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AlertListener.java new file mode 100755 index 000000000..7686c6082 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AlertListener.java @@ -0,0 +1,245 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UOctet; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.alert.consumer.AlertAdapter; +import org.ccsds.moims.mo.mc.structures.AlertConfigurationList; + +public class AlertListener extends AlertAdapter { + + static class MonitorAlertUpdate { + IdentifierList domain; + Identifier alertKey; + UInteger alertVersion; + UOctet alertSeverity; + Time timestamp; + NullableAttributeList arguments; + public MonitorAlertUpdate( + IdentifierList domain, + Identifier alertKey, + UInteger alertVersion, + UOctet alertSeverity, + Time timestamp, + NullableAttributeList arguments) { + this.domain = domain; + this.alertKey = alertKey; + this.alertVersion = alertVersion; + this.alertSeverity = alertSeverity; + this.timestamp = timestamp; + this.arguments = arguments; + } + } + + String testException = null; + MOErrorException error = null; + boolean registerAckReceived = false; + boolean deregisterAckReceived = false; + boolean enableGenerationAckReceived = false; + boolean disableGenerationAckReceived = false; + AlertConfigurationList getAlertConfigurationResponse = null; + ConcurrentLinkedQueue alertUpdates = new ConcurrentLinkedQueue<>(); + + synchronized void reset() { + testException = null; + error = null; + registerAckReceived = false; + deregisterAckReceived = false; + enableGenerationAckReceived = false; + disableGenerationAckReceived = false; + getAlertConfigurationResponse = null; + alertUpdates.clear(); + } + + public boolean hasError() { + return testException != null || error != null; + } + public String getError() { + if (error != null) + return error.toString(); + return testException; + } + + private void addTestException(String testException) { + if (this.testException == null) + this.testException = testException; + } + + @Override + public void enableGenerationAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: enableGenerationAckReceived()"); + synchronized(this) { + enableGenerationAckReceived = true; + notify(); + } + } + @Override + public void enableGenerationErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: enableGenerationErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void disableGenerationAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: disableGenerationAckReceived()"); + synchronized(this) { + disableGenerationAckReceived = true; + notify(); + } + } + @Override + public void disableGenerationErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: disableGenerationErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void getAlertConfigurationResponseReceived( + MALMessageHeader msgHeader, + AlertConfigurationList alertConfigs, + java.util.Map qosProperties) { + System.out.println("Reached: getAlertConfigurationResponseReceived()"); + if (alertConfigs == null) { + // OUT field is not nullable + addTestException("getAlertConfiguration OUT parameter is null"); + } + synchronized(this) { + this.getAlertConfigurationResponse = alertConfigs; + notify(); + } + } + @Override + public void getAlertConfigurationErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: getAlertConfigurationErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void monitorAlertRegisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: monitorAlertRegisterAckReceived()"); + synchronized(this) { + registerAckReceived = true; + notify(); + } + } + @Override + public void monitorAlertRegisterErrorReceived( + MALMessageHeader msgHeader, + org.ccsds.moims.mo.mal.MOErrorException error, + Map qosProperties) { + System.out.println("Reached: monitorAlertRegisterErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void monitorAlertNotifyReceived( + MALMessageHeader msgHeader, + Identifier subscriptionId, + UpdateHeader updateHeader, + Time timestamp, + NullableAttributeList arguments, + Map qosProperties) { + System.out.println("Reached: monitorAlertNotifyReceived() -> " + timestamp + " " + arguments); + // all subscription keys are used in all the tests + NullableAttributeList keyValues = updateHeader.getKeyValues(); + Identifier alertKey = null; + UInteger alertVersion = null; + UOctet alertSeverity = null; + if (keyValues == null || keyValues.size() != 3) { + addTestException("Unexpected number of subscription key values"); + } else { + Attribute aKey = keyValues.get(0).getValue(); + if (aKey != null) + alertKey = (Identifier) aKey; + Attribute aVersion = keyValues.get(1).getValue(); + if (aVersion != null) + alertVersion = (UInteger) aVersion; + Attribute aSeverity = keyValues.get(2).getValue(); + if (aSeverity != null) + alertSeverity = (UOctet) aSeverity; + } + synchronized(this) { + alertUpdates.add(new MonitorAlertUpdate( + updateHeader.getDomain(), + alertKey, alertVersion, alertSeverity, + timestamp, arguments)); + notify(); + } + } + @Override + public void monitorAlertNotifyErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: monitorAlertNotifyErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void monitorAlertDeregisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: monitorAlertDeregisterAckReceived()"); + synchronized(this) { + deregisterAckReceived = true; + notify(); + } + } + +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AlertTestClient.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AlertTestClient.java new file mode 100755 index 000000000..f851a41c1 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/AlertTestClient.java @@ -0,0 +1,520 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.Iterator; +import org.ccsds.mo.mc.testbed.AlertListener.MonitorAlertUpdate; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mc.structures.AlertConfiguration; +import org.ccsds.moims.mo.mc.structures.AlertConfigurationList; + +/** +* This class provides shared functions for all Alert test clients. +*/ +public class AlertTestClient extends MCTest { + + protected static void execAndCheckMonitorAlertRegister( + Subscription subscription, + AlertListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + alertConsumerStub.asyncMonitorAlertRegister( + subscription, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.registerAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate it + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.registerAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckMonitorAlertDeregister( + IdentifierList subscriptions, + AlertListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + alertConsumerStub.asyncMonitorAlertDeregister( + subscriptions, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.deregisterAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate it + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.deregisterAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + /** + * Waits for expected updates and checks them. + * + * @param listener callback listener + * @param maxTime max waiting time + * @param updates expected updates + */ + protected static void waitAndCheckForUpdates( + AlertListener listener, + long maxTime, + MonitorAlertUpdate[] updates) { + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + int nbUpdates = updates.length; + synchronized(listener) { + while (!listener.hasError() && + listener.alertUpdates.size() != nbUpdates && + timeout > 0) { + try { + System.out.println("wait for Updates from subscription"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + System.out.println("end wait, listener=" + listener); + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.alertUpdates.size() != nbUpdates) + unitTestFail("Incorrect number of updates received: " + + "expected " + nbUpdates + + " was " + listener.alertUpdates.size()); + // check received updates + Iterator it = listener.alertUpdates.iterator(); + for (int idx = 0; it.hasNext(); idx++) { + assertEquals("Update[" + idx + "]", updates[idx], it.next()); + } + } + } + + protected static void waitAndCheckNoUpdate( + AlertListener listener, + long maxTime) { + // ------------------------------------------------------------------------ + // Wait for TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + synchronized(listener) { + while (!listener.hasError() && + timeout > 0) { + try { + System.out.println("wait for timeout"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + + // check no new message from subscription + if (!listener.alertUpdates.isEmpty()) + unitTestFail("received unexpected updates"); + } + } + + protected static void execAndCheckGetAlertConfiguration( + IdentifierList domain, + IdentifierList keys, + AlertListener listener, + long maxTime, + AlertConfigurationList expected) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + alertConsumerStub.asyncGetAlertConfiguration( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for response or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.getAlertConfigurationResponse == null && + timeout > 0) { + try { + System.out.println("wait for response"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.getAlertConfigurationResponse == null) + unitTestFail("The RESPONSE was not received!"); + + assertEquals( + "error in getAlertConfiguration RESPONSE", + expected, + listener.getAlertConfigurationResponse); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorGetAlertConfiguration( + IdentifierList domain, + IdentifierList keys, + AlertListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + alertConsumerStub.asyncGetAlertConfiguration( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for response or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.getAlertConfigurationResponse == null && + timeout > 0) { + try { + System.out.println("wait for response"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.getAlertConfigurationResponse != null) + unitTestFail("Unexpected RESPONSE received"); + if (listener.error == null) + unitTestFail("Missing expected response error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckEnableGeneration( + IdentifierList domain, + IdentifierList keys, + AlertListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + alertConsumerStub.asyncEnableGeneration( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.enableGenerationAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.enableGenerationAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorEnableGeneration( + IdentifierList domain, + IdentifierList keys, + AlertListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + alertConsumerStub.asyncEnableGeneration( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.enableGenerationAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.enableGenerationAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckDisableGeneration( + IdentifierList domain, + IdentifierList keys, + AlertListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + alertConsumerStub.asyncDisableGeneration( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.disableGenerationAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.disableGenerationAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorDisableGeneration( + IdentifierList domain, + IdentifierList keys, + AlertListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + alertConsumerStub.asyncDisableGeneration( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.disableGenerationAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.disableGenerationAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void assertEquals( + String error, + MonitorAlertUpdate expected, + MonitorAlertUpdate actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + ", expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + ", expecting " + expected + ", was " + actual); + if (!actual.domain.equals(expected.domain)) + unitTestFail(error + " unexpected domain" + + ", expecting " + expected.domain + + ", was " + actual.domain); + if (!actual.alertKey.equals(expected.alertKey)) + unitTestFail(error + " unexpected alertKey subscription key" + + ", expecting " + expected.alertKey + + ", was " + actual.alertKey); + if (!actual.alertSeverity.equals(expected.alertSeverity)) + unitTestFail(error + " unexpected alertSeverity subscription key" + + ", expecting " + expected.alertSeverity + + ", was " + actual.alertSeverity); + if (!actual.alertVersion.equals(expected.alertVersion)) + unitTestFail(error + " unexpected alertVersion subscription key" + + ", expecting " + expected.alertVersion + + ", was " + actual.alertVersion); + assertEquals(error + " arguments", expected.arguments, actual.arguments); + } + + public static void assertEquals(String error, AlertConfigurationList expected, AlertConfigurationList actual) { + if (expected == null) { + if (actual != null) + unitTestFail(error + " unexpected list, expecting null, was " + actual); + return; + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); + } + } + public static void assertEquals(String error, AlertConfiguration expected, AlertConfiguration actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected value, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); + if (expected.getGenerationEnabled() == null && actual.getGenerationEnabled() != null || + expected.getGenerationEnabled() != null && !expected.getGenerationEnabled().equals(actual.getGenerationEnabled())) + unitTestFail(error + " unexpected generationEnabled, expecting " + expected.getGenerationEnabled() + ", was " + actual.getGenerationEnabled()); + } +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/MCTest.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/MCTest.java index caf3596fb..c06f477dc 100644 --- a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/MCTest.java +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/MCTest.java @@ -4,7 +4,14 @@ * Darmstadt * Germany * ---------------------------------------------------------------------------- +<<<<<<< HEAD * System : CCSDS MO Testbed +======= + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C +>>>>>>> 1644edb5 (M&C testbed) * ---------------------------------------------------------------------------- * Licensed under the European Space Agency Public License, Version 2.0 * You may not use this file except in compliance with the License. @@ -20,12 +27,33 @@ */ package org.ccsds.mo.mc.testbed; -import org.ccsds.mo.mc.testbed.SetUpProvidersAndConsumers; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.SetUpProvidersAndConsumers; +import org.ccsds.mo.mc.testbed.AlertListener.MonitorAlertUpdate; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Element; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectIdentity; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mal.structures.ULong; +import org.ccsds.moims.mo.mal.structures.UOctet; import org.ccsds.moims.mo.mal.structures.URI; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mc.ActionDataset; import org.ccsds.moims.mo.mc.action.consumer.ActionStub; import org.ccsds.moims.mo.mc.action.provider.ActionInheritanceSkeleton; import org.ccsds.moims.mo.mc.aggregation.consumer.AggregationStub; @@ -36,76 +64,594 @@ import org.ccsds.moims.mo.mc.packet.provider.PacketInheritanceSkeleton; import org.ccsds.moims.mo.mc.parameter.consumer.ParameterStub; import org.ccsds.moims.mo.mc.parameter.provider.ParameterInheritanceSkeleton; +import org.ccsds.moims.mo.mc.structures.ActionCompleteEvent; +import org.ccsds.moims.mo.mc.structures.ActionEvent; +import org.ccsds.moims.mo.mc.structures.ActionInProgressEvent; +import org.ccsds.moims.mo.mc.structures.ActionStartEvent; +import org.ccsds.moims.mo.mc.structures.AggregationValue; +import org.ccsds.moims.mo.mc.structures.AggregationValueList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueDataList; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; +import org.ccsds.moims.mo.mc.structures.Severity; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; +import static org.junit.Assert.*; + /** - * The abstract class for all MC Tests. + * The abstract class for all M&C Tests. * * @author Cesar.Coelho */ public abstract class MCTest { - protected static final int TIMEOUT = 500; // In milliseconds - protected static final String TEST_START = "-------- Running New Test --------"; - protected static final String TEST_END = "Test is completed!"; - protected static final String TEST_SET_UP_CLASS_1 = "-----------------------------------------------------------------------"; - protected static final String TEST_SET_UP_CLASS_2 = "Entered: setUpClass() - The Provider and Consumer will be started here!"; - protected static final SetUpProvidersAndConsumers setUp = new SetUpProvidersAndConsumers(); - - protected static ActionInheritanceSkeleton actionProviderService = null; - protected static ActionStub actionConsumerStub = null; - protected static AggregationInheritanceSkeleton aggregationProviderService = null; - protected static AggregationStub aggregationConsumerStub = null; - protected static AlertInheritanceSkeleton alertProviderService = null; - protected static AlertStub alertConsumerStub = null; - protected static PacketInheritanceSkeleton packetProviderService = null; - protected static PacketStub packetConsumerStub = null; - protected static ParameterInheritanceSkeleton parameterProviderService = null; - protected static ParameterStub parameterConsumerStub = null; - - @AfterClass - public static void tearDownClass() { - System.out.println("Entered: tearDownClass()"); - System.out.println("The Provider and Consumer are being closed!"); - - try { - setUp.tearDown(); // Close all the services - } catch (IOException ex) { - Logger.getLogger(MCTest.class.getName()).log(Level.SEVERE, - "The tearDown() operation failed!", ex); - } - } - - @Before - public void setUp() { - System.out.println(TEST_START); // Right before running a test - actionProviderService = setUp.getActionProvider(); - actionConsumerStub = setUp.getActionConsumer(); - aggregationProviderService = setUp.getAggregationProvider(); - aggregationConsumerStub = setUp.getAggregationConsumer(); - alertProviderService = setUp.getAlertProvider(); - alertConsumerStub = setUp.getAlertConsumer(); - packetProviderService = setUp.getPacketProvider(); - packetConsumerStub = setUp.getPacketConsumer(); - parameterProviderService = setUp.getParameterProvider(); - parameterConsumerStub = setUp.getParameterConsumer(); - } - - @After - public void tearDown() { - System.out.println(TEST_END); - } - - protected static URI getHomeTmpDir() { - File homeDirectory = new File(System.getProperty("user.home")); - File targetDir = new File(homeDirectory, "tmp"); - if (!targetDir.exists()) { - // Create the directory if it does not exist: - targetDir.mkdirs(); - } - return new URI("file://" + targetDir.getAbsolutePath()); - } + private static final Logger logger = Logger.getLogger(MCTest.class.getName()); + protected static final int TIMEOUT = 500; // In milliseconds + protected static final int NOUPDATE_TIMEOUT = 50; // In milliseconds + protected static final String TEST_START = "-------- Running New Test --------"; + protected static final String TEST_END = "Test is completed!"; + protected static final String TEST_SET_UP_CLASS_1 = "-----------------------------------------------------------------------"; + protected static final String TEST_SET_UP_CLASS_2 = "Entered: setUpClass() - The Provider and Consumer will be started here!"; + protected static final SetUpProvidersAndConsumers setUp = new SetUpProvidersAndConsumers(); + + protected static ActionInheritanceSkeleton actionProviderService = null; + protected static ActionStub actionConsumerStub = null; + protected static AggregationInheritanceSkeleton aggregationProviderService = null; + protected static AggregationStub aggregationConsumerStub = null; + protected static AlertInheritanceSkeleton alertProviderService = null; + protected static AlertStub alertConsumerStub = null; + protected static PacketInheritanceSkeleton packetProviderService = null; + protected static PacketStub packetConsumerStub = null; + protected static ParameterInheritanceSkeleton parameterProviderService = null; + protected static ParameterStub parameterConsumerStub = null; + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: tearDownClass()"); + System.out.println("The Provider and Consumer are being closed!"); + + try { + setUp.tearDown(); // Close all the services + } catch (IOException ex) { + Logger.getLogger(MCTest.class.getName()).log(Level.SEVERE, + "The tearDown() operation failed!", ex); + } + } + + @Before + public void setUp() { + System.out.println(TEST_START); // Right before running a test + actionProviderService = setUp.getActionProvider(); + actionConsumerStub = setUp.getActionConsumer(); + aggregationProviderService = setUp.getAggregationProvider(); + aggregationConsumerStub = setUp.getAggregationConsumer(); + alertProviderService = setUp.getAlertProvider(); + alertConsumerStub = setUp.getAlertConsumer(); + packetProviderService = setUp.getPacketProvider(); + packetConsumerStub = setUp.getPacketConsumer(); + parameterProviderService = setUp.getParameterProvider(); + parameterConsumerStub = setUp.getParameterConsumer(); + } + + @After + public void tearDown() { + System.out.println(TEST_END); + } + + protected static URI getHomeTmpDir() { + File homeDirectory = new File(System.getProperty("user.home")); + File targetDir = new File(homeDirectory, "tmp"); + if (!targetDir.exists()) { + // Create the directory if it does not exist: + targetDir.mkdirs(); + } + return new URI("file://" + targetDir.getAbsolutePath()); + } + + // factorize the logging stuff + private static Logger unitTestLogger; + protected static void setUnitTestLogger(Logger logger) { + unitTestLogger = logger; + } + protected static void unitTestFail(String message) { + unitTestLogger.log(Level.SEVERE, message); + fail(message); + } + protected static void unitTestFail(Throwable thrown) { + unitTestLogger.log(Level.SEVERE, null, thrown); + fail(thrown.toString()); + } + + protected static void assertEqualsUpdateHeaders(String error, Iterable expected, Iterable actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + Iterator eit = expected.iterator(); + Iterator ait = actual.iterator(); + int eltIdx = 1; + while (eit.hasNext()) { + if (!ait.hasNext()) + unitTestFail(error + " missing update header #" + eltIdx); + assertEquals(error + " event #" + eltIdx, eit.next(), ait.next()); + eltIdx++; + } + } + protected static void assertEquals(String error, UpdateHeader expected, UpdateHeader actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + ", expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + ", expecting " + expected + ", was " + actual); + // check domain and key values + if (expected.getDomain() == null) { + if (actual.getDomain() != null) + unitTestFail(error + " wrong domain" + + ", expected " + expected.getDomain() + ", was " + actual.getDomain()); + } else if (!expected.getDomain().equals(actual.getDomain())) { + unitTestFail(error + " wrong domain" + + ", expected " + expected.getDomain() + ", was " + actual.getDomain()); + } + assertEquals(error + " wrong key values", expected.getKeyValues(), actual.getKeyValues()); + } + + protected static void assertEqualsActionEvents(String error, Iterable expected, Iterable actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + Iterator eit = expected.iterator(); + Iterator ait = actual.iterator(); + int eventIdx = 1; + while (eit.hasNext()) { + if (!ait.hasNext()) + unitTestFail(error + " missing event #" + eventIdx); + assertEquals(error + " event #" + eventIdx, eit.next(), ait.next()); + eventIdx++; + } + } + protected static void assertEquals(String error, ActionEvent expected, ActionEvent actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected event, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected event, expecting " + expected + ", was " + actual); + if (actual.getSuccess() != expected.getSuccess()) + unitTestFail(error + " unexpected success field, expecting " + expected.getSuccess() + ", was " + actual.getSuccess()); + if (expected instanceof ActionStartEvent) { + if (!(actual instanceof ActionStartEvent)) + unitTestFail(error + " unexpected event type, expecting " + expected.getClass().getName() + ", was " + actual.getClass().getName()); + } else if (expected instanceof ActionCompleteEvent) { + if (!(actual instanceof ActionCompleteEvent)) + unitTestFail(error + " unexpected event type, expecting " + expected.getClass().getName() + ", was " + actual.getClass().getName()); + } else if (expected instanceof ActionInProgressEvent) { + if (!(actual instanceof ActionInProgressEvent)) + unitTestFail(error + " unexpected event type, expecting " + expected.getClass().getName() + ", was " + actual.getClass().getName()); + ActionInProgressEvent eipEvent = (ActionInProgressEvent) expected; + ActionInProgressEvent aipEvent = (ActionInProgressEvent) actual; + if (!eipEvent.getStageCount().equals(aipEvent.getStageCount())) + unitTestFail(error + " unexpected stageCount field, expecting " + eipEvent.getStageCount() + ", was " + aipEvent.getStageCount()); + if (!eipEvent.getExecutionStage().equals(aipEvent.getExecutionStage())) + unitTestFail(error + " unexpected executionStage field, expecting " + eipEvent.getExecutionStage() + ", was " + aipEvent.getExecutionStage()); + } + } + + protected static void assertEquals(String error, NullableAttributeList expected, NullableAttributeList actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); + } + } + protected static void assertEquals(String error, NullableAttribute expected, NullableAttribute actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected nullable attribute, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected nullable attribute, expecting " + expected + ", was " + actual); + assertEquals(error, expected.getValue(), actual.getValue()); + } + protected static void assertEquals(String error, Attribute expected, Attribute actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected attribute, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected attribute, expecting " + expected + ", was " + actual); + if (!expected.equals(actual)) + unitTestFail(error + " unexpected attribute, expecting " + expected + ", was " + actual); + } + + protected static void assertEquals(String error, UIntegerList expected, UIntegerList actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); + } + } + protected static void assertEquals(String error, UInteger expected, UInteger actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected value, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); + if (!expected.equals(actual)) + unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); + } + + // test values used in Parameter and Alert tests + public static final NullableAttribute NA_DOUBLE_910 = new NullableAttribute(new Union(new Double(9.10e0))); + public static final NullableAttribute NA_DOUBLE_920 = new NullableAttribute(new Union(new Double(9.20e0))); + public static final NullableAttribute NA_DOUBLE_1200 = new NullableAttribute(new Union(new Double(12.00e0))); + public static final NullableAttribute NA_DOUBLE_1204 = new NullableAttribute(new Union(new Double(12.04e0))); + public static final NullableAttribute NA_DOUBLE_1205 = new NullableAttribute(new Union(new Double(12.05e0))); + public static final NullableAttribute NA_DOUBLE_1208 = new NullableAttribute(new Union(new Double(12.08e0))); + public static final NullableAttribute NA_DOUBLE_1210 = new NullableAttribute(new Union(new Double(12.10e0))); + public static final NullableAttribute NA_DOUBLE_1211 = new NullableAttribute(new Union(new Double(12.11e0))); + public static final NullableAttribute NA_DOUBLE_1215 = new NullableAttribute(new Union(new Double(12.15e0))); + public static final NullableAttribute NA_DOUBLE_1220 = new NullableAttribute(new Union(new Double(12.20e0))); + public static final NullableAttribute NA_DOUBLE_1300 = new NullableAttribute(new Union(new Double(13.00e0))); + public static final NullableAttribute NA_DOUBLE_1304 = new NullableAttribute(new Union(new Double(13.04e0))); + public static final NullableAttribute NA_DOUBLE_1305 = new NullableAttribute(new Union(new Double(13.05e0))); + public static final NullableAttribute NA_DOUBLE_1315 = new NullableAttribute(new Union(new Double(13.15e0))); + public static final NullableAttribute NA_DOUBLE_1903 = new NullableAttribute(new Union(new Double(19.03e0))); + public static final NullableAttribute NA_DOUBLE_1904 = new NullableAttribute(new Union(new Double(19.04e0))); + public static final NullableAttribute NA_DOUBLE_1905 = new NullableAttribute(new Union(new Double(19.05e0))); + public static final NullableAttribute NA_DOUBLE_2200 = new NullableAttribute(new Union(new Double(22.00e0))); + public static final NullableAttribute NA_UINT_1 = new NullableAttribute(new UInteger(1)); + public static final NullableAttribute NA_UINT_2 = new NullableAttribute(new UInteger(2)); + public static final NullableAttribute NA_UINT_8 = new NullableAttribute(new UInteger(8)); + public static final NullableAttribute NA_STRING_ENABLED = new NullableAttribute(new Union(Constant.STR_ENABLED)); + public static final NullableAttribute NA_STRING_DISABLED = new NullableAttribute(new Union(Constant.STR_DISABLED)); + public static final NullableAttribute NA_STRING_UNKNOWN = new NullableAttribute(new Union(Constant.STR_UNKNOWN)); + + // UOctet value of the Severity.SEVERE enumeration value + public static final UOctet UO_SEVERE = new UOctet(Severity.SEVERE.getValue()); + + // subscription key values used in Packet tests + public static final NullableAttribute NA_USHORT_3 = new NullableAttribute(new UShort(3)); + public static final NullableAttribute NA_USHORT_4 = new NullableAttribute(new UShort(4)); + public static final NullableAttribute NA_UOCTET_11 = new NullableAttribute(new UOctet(11)); + public static final NullableAttribute NA_UOCTET_12 = new NullableAttribute(new UOctet(12)); + public static final NullableAttribute NA_NULL = new NullableAttribute(null); + + // extra info values + public static final UIntegerList EXTRA_UIL_0 = + new UIntegerList(new ArrayList<>(Arrays.asList( + new UInteger(0)))); + public static final UIntegerList EXTRA_UIL_1 = + new UIntegerList(new ArrayList<>(Arrays.asList( + new UInteger(1)))); +// +// public void waitAndCheckForParameterMonitorValueUpdates( +// ParameterListener parameterListener, long maxtime, ParameterListener.MonitorValueUpdate[] updates) { +// // ------------------------------------------------------------------------ +// // Wait for all updates or TIMOUT +// long timeout = maxtime - System.currentTimeMillis(); +// int nbUpdates = updates.length; +// synchronized(parameterListener) { +// while (!parameterListener.hasError() && +// parameterListener.valueUpdates.size() != nbUpdates && +// timeout > 0) { +// try { +// System.out.println("wait for Updates from subscription"); +// parameterListener.wait(timeout); +// } catch (InterruptedException e) {} +// // Recalculate timer +// timeout = maxtime - System.currentTimeMillis(); +// } +// System.out.println("end wait, parameterListener=" + parameterListener); +// if (parameterListener.hasError()) +// unitTestFail(parameterListener.getError()); +// if (parameterListener.valueUpdates.size() != nbUpdates) +// unitTestFail("Incorrect number of updates received: " + +// "expected " + nbUpdates + +// " was " + parameterListener.valueUpdates.size()); +// // check received updates +// Iterator it = parameterListener.valueUpdates.iterator(); +// for (int idx = 0; it.hasNext(); idx++) { +// String error = "Update[" + idx + "]"; +// ParameterListener.MonitorValueUpdate update = it.next(); +// if (!update.domain.equals(updates[idx].domain)) +// unitTestFail(error + " unexpected domain, expecting " + updates[idx].domain + ", was " + update.domain); +// if (!update.parameterKey.equals(updates[idx].parameterKey)) +// unitTestFail(error + " unexpected parameterKey subscription key, expecting " + updates[idx].parameterKey + ", was " + update.parameterKey); +// if (!update.parameterVersion.equals(updates[idx].parameterVersion)) +// unitTestFail(error + " unexpected parameterVersion subscription key, expecting " + updates[idx].parameterVersion + ", was " + update.parameterVersion); +// assertEquals(error + " value data", updates[idx].newValue, update.newValue); +// } +// } +// } +// +// public void waitAndCheckForAggregationMonitorValueUpdates( +// AggregationListener aggregationListener, long maxtime, AggregationListener.MonitorValueUpdate[] updates) { +// // ------------------------------------------------------------------------ +// // Wait for all updates or TIMOUT +// long timeout = maxtime - System.currentTimeMillis(); +// int nbUpdates = updates.length; +// synchronized(aggregationListener) { +// while (!aggregationListener.hasError() && +// aggregationListener.valueUpdates.size() != nbUpdates && +// timeout > 0) { +// try { +// System.out.println("wait for Updates from subscription"); +// aggregationListener.wait(timeout); +// } catch (InterruptedException e) {} +// // Recalculate timer +// timeout = maxtime - System.currentTimeMillis(); +// } +// System.out.println("end wait, parameterListener=" + aggregationListener); +// if (aggregationListener.hasError()) +// unitTestFail(aggregationListener.getError()); +// if (aggregationListener.valueUpdates.size() != nbUpdates) +// unitTestFail("Incorrect number of updates received: " + +// "expected " + nbUpdates + +// " was " + aggregationListener.valueUpdates.size()); +// // check received updates +// Iterator it = aggregationListener.valueUpdates.iterator(); +// for (int idx = 0; it.hasNext(); idx++) { +// String error = "Update[" + idx + "]"; +// AggregationListener.MonitorValueUpdate update = it.next(); +// if (!update.domain.equals(updates[idx].domain)) +// unitTestFail(error + " unexpected domain, expecting " + updates[idx].domain + ", was " + update.domain); +// if (!update.aggregationKey.equals(updates[idx].aggregationKey)) +// unitTestFail(error + " unexpected aggregationKey subscription key, expecting " + updates[idx].aggregationKey + ", was " + update.aggregationKey); +// if (!update.aggregationVersion.equals(updates[idx].aggregationVersion)) +// unitTestFail(error + " unexpected aggregationVersion subscription key, expecting " + updates[idx].aggregationVersion + ", was " + update.aggregationVersion); +// assertEquals(error + " values", updates[idx].values, update.values); +// } +// } +// } +// +// public void waitAndCheckForMonitorAlertUpdates(AlertListener alertListener, long maxtime, MonitorAlertUpdate[] updates) { +// // ------------------------------------------------------------------------ +// // Wait for all updates or TIMOUT +// long timeout = maxtime - System.currentTimeMillis(); +// int nbUpdates = updates.length; +// synchronized(alertListener) { +// while (!alertListener.hasError() && +// alertListener.alertUpdates.size() != nbUpdates && +// timeout > 0) { +// try { +// System.out.println("wait for Updates from subscription"); +// alertListener.wait(timeout); +// } catch (InterruptedException e) {} +// // Recalculate timer +// timeout = maxtime - System.currentTimeMillis(); +// } +// System.out.println("end wait, alertListener=" + alertListener); +// if (alertListener.hasError()) +// unitTestFail(alertListener.getError()); +// if (alertListener.alertUpdates.size() != nbUpdates) +// unitTestFail("Incorrect number of updates received: " + +// "expected " + nbUpdates + +// " was " + alertListener.alertUpdates.size()); +// // check received updates +// Iterator it = alertListener.alertUpdates.iterator(); +// for (int idx = 0; it.hasNext(); idx++) { +// String error = "Update[" + idx + "]"; +// MonitorAlertUpdate update = it.next(); +// if (!update.domain.equals(updates[idx].domain)) +// unitTestFail(error + " unexpected domain, expecting " + updates[idx].domain + ", was " + update.domain); +// if (!update.alertKey.equals(updates[idx].alertKey)) +// unitTestFail(error + " unexpected alertKey subscription key, expecting " + updates[idx].alertKey + ", was " + update.alertKey); +// if (!update.alertSeverity.equals(updates[idx].alertSeverity)) +// unitTestFail(error + " unexpected alertSeverity subscription key, expecting " + updates[idx].alertSeverity + ", was " + update.alertSeverity); +// if (!update.alertVersion.equals(updates[idx].alertVersion)) +// unitTestFail(error + " unexpected alertVersion subscription key, expecting " + updates[idx].alertVersion + ", was " + update.alertVersion); +// assertEquals(error + " arguments", updates[idx].arguments, update.arguments); +// } +// } +// } +// +// public void waitAndCheckForDeliverPacketUpdates( +// PacketListener packetListener, +// long maxtime, +// PacketListener.DeliverPacketUpdate[] updates) { +// // ------------------------------------------------------------------------ +// // Wait for all updates or TIMOUT +// long timeout = maxtime - System.currentTimeMillis(); +// int nbUpdates = updates.length; +// synchronized(packetListener) { +// while (!packetListener.hasError() && +// packetListener.packetUpdates.size() != nbUpdates && +// timeout > 0) { +// try { +// System.out.println("wait for Updates from subscription"); +// packetListener.wait(timeout); +// } catch (InterruptedException e) {} +// // Recalculate timer +// timeout = maxtime - System.currentTimeMillis(); +// } +// System.out.println("end wait, packetListener=" + packetListener); +// if (packetListener.hasError()) +// unitTestFail(packetListener.getError()); +// if (packetListener.packetUpdates.size() != nbUpdates) +// unitTestFail("Incorrect number of updates received: " + +// "expected " + nbUpdates + +// " was " + packetListener.packetUpdates.size()); +// // check received updates +// Iterator it = packetListener.packetUpdates.iterator(); +// for (int idx = 0; it.hasNext(); idx++) { +// String error = "Update[" + idx + "]"; +// PacketListener.DeliverPacketUpdate update = it.next(); +// if (!update.domain.equals(updates[idx].domain)) +// unitTestFail(error + " unexpected domain, expecting " + updates[idx].domain + ", was " + update.domain); +// if (!update.apid.equals(updates[idx].apid)) +// unitTestFail(error + " unexpected apid subscription key, expecting " + updates[idx].apid + ", was " + update.apid); +// if (!update.destID.equals(updates[idx].destID)) +// unitTestFail(error + " unexpected destID subscription key, expecting " + updates[idx].destID + ", was " + update.destID); +// assertEquals(error + " packet", updates[idx].spacePacket, update.spacePacket); +// } +// } +// } +// +// public static void assertEquals(String error, ParameterValueList expected, ParameterValueList actual) { +// if (expected == null) { +// if (actual == null) +// return; +// unitTestFail(error + " unexpected list, expecting null, was " + actual); +// } +// if (actual == null) +// unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); +// if (actual.size() != expected.size()) +// unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); +// for (int i = 0; i < expected.size(); i++) { +// assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); +// } +// } +// public static void assertEquals(String error, ParameterValue expected, ParameterValue actual) { +// if (expected == null) { +// if (actual == null) +// return; +// unitTestFail(error + " unexpected value, expecting null, was " + actual); +// } +// if (actual == null) +// unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); +// assertEquals(error + " paramRef", expected.getParamRef(), actual.getParamRef()); +// // ignore timestamp and samplingTime +// assertEquals(error + " value", expected.getValue(), actual.getValue()); +// } +// public static void assertEquals(String error, ParameterValueDataList expected, ParameterValueDataList actual) { +// if (expected == null) { +// if (actual == null) +// return; +// unitTestFail(error + " unexpected list, expecting null, was " + actual); +// } +// if (actual == null) +// unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); +// if (actual.size() != expected.size()) +// unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); +// for (int i = 0; i < expected.size(); i++) { +// assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); +// } +// } +// public static void assertEquals(String error, ParameterValueData expected, ParameterValueData actual) { +// if (expected == null) { +// if (actual == null) +// return; +// unitTestFail(error + " unexpected value, expecting null, was " + actual); +// } +// if (actual == null) +// unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); +// if (!expected.getValidityState().equals(actual.getValidityState())) +// unitTestFail(error + " unexpected validity state, expecting " + expected.getValidityState() + ", was " + actual.getValidityState()); +// if (expected.getRawValue() == null && actual.getRawValue() != null || +// expected.getRawValue() != null && !expected.getRawValue().equals(actual.getRawValue())) +// unitTestFail(error + " unexpected raw value, expecting " + expected.getRawValue() + ", was " + actual.getRawValue()); +// if (expected.getConvertedValue() == null && actual.getConvertedValue() != null || +// expected.getConvertedValue() != null && !expected.getConvertedValue().equals(actual.getConvertedValue())) +// unitTestFail(error + " unexpected converted value, expecting " + expected.getConvertedValue() + ", was " + actual.getConvertedValue()); +// } +// +// public static void assertEquals(String error, ReportConfigurationList expected, ReportConfigurationList actual) { +// if (expected == null) { +// if (actual != null) +// unitTestFail(error + " unexpected list, expecting null, was " + actual); +// return; +// } +// if (actual == null) +// unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); +// if (actual.size() != expected.size()) +// unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); +// for (int i = 0; i < expected.size(); i++) { +// assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); +// } +// } +// public static void assertEquals(String error, ReportConfiguration expected, ReportConfiguration actual) { +// if (expected == null) { +// if (actual == null) +// return; +// unitTestFail(error + " unexpected value, expecting null, was " + actual); +// } +// if (actual == null) +// unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); +// if (expected.getGenerationEnabled() == null && actual.getGenerationEnabled() != null || +// expected.getGenerationEnabled() != null && !expected.getGenerationEnabled().equals(actual.getGenerationEnabled())) +// unitTestFail(error + " unexpected generationEnabled, expecting " + expected.getGenerationEnabled() + ", was " + actual.getGenerationEnabled()); +// if (expected.getReportInterval() == null && actual.getReportInterval() != null || +// expected.getReportInterval() != null && !expected.getReportInterval().equals(actual.getReportInterval())) +// unitTestFail(error + " unexpected reportInterval, expecting " + expected.getReportInterval() + ", was " + actual.getReportInterval()); +// } +// +// public static void assertEquals(String error, ObjectRef expected, ObjectRef actual) { +// if (expected == null) { +// if (actual == null) +// return; +// unitTestFail(error + " unexpected value, expecting null, was " + actual); +// } +// if (actual == null) +// unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); +// if (!expected.getDomain().equals(actual.getDomain())) +// unitTestFail(error + " unexpected domain, expecting " + expected.getDomain() + ", was " + actual.getDomain()); +// if (!expected.getKey().equals(actual.getKey())) +// unitTestFail(error + " unexpected key, expecting " + expected.getKey() + ", was " + actual.getKey()); +// if (!expected.getTypeId().equals(actual.getTypeId())) +// unitTestFail(error + " unexpected type, expecting " + expected.getTypeId() + ", was " + actual.getTypeId()); +// if (!expected.getObjectVersion().equals(actual.getObjectVersion())) +// unitTestFail(error + " unexpected version, expecting " + expected.getObjectVersion() + ", was " + actual.getObjectVersion()); +// } +// public static void assertEquals(String error, AggregationValueList expected, AggregationValueList actual) { +// if (expected == null) { +// if (actual == null) +// return; +// unitTestFail(error + " unexpected list, expecting null, was " + actual); +// } +// if (actual == null) +// unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); +// if (actual.size() != expected.size()) +// unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); +// for (int i = 0; i < expected.size(); i++) { +// assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); +// } +// } +// public static void assertEquals(String error, AggregationValue expected, AggregationValue actual) { +// if (expected == null) { +// if (actual == null) +// return; +// unitTestFail(error + " unexpected value, expecting null, was " + actual); +// } +// if (actual == null) +// unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); +// assertEquals(error + " aggregRef", expected.getAggregationRef(), actual.getAggregationRef()); +// // ignore timestamp +// assertEquals(error + " parameter values", expected.getParameterValues(), actual.getParameterValues()); +// } + } diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_1_Basic_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_1_Basic_Test.java new file mode 100755 index 000000000..dd01f6396 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_1_Basic_Test.java @@ -0,0 +1,255 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.ParameterListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterBasicDataset; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * PA_1_Basic_Test implements the test scenario #PA-1. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PA_1_Basic_Test extends ParameterTestClient { + + static ParameterListener parameterListener = new ParameterListener(); + static Identifier subscriptionId; + + // initialize BackendTimer with timeOrigin + // timeOrigin=1/1/2025 01:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 1, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterBasicDataset backend = new ParameterBasicDataset(timer); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(PA_1_Basic_Test.class.getName())); + setUp.setUp(null, null, null, null, backend, + false, false, false, false, true); + parameterConsumerStub = setUp.getParameterConsumer(); + + // call monitorValue.register with subscription + // subscription= + // - subscriptionId=11 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("11"); + execAndCheckMonitorValueRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + parameterListener, + System.currentTimeMillis() + TIMEOUT); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + PA_1_Basic_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + parameterListener.reset(); + execAndCheckMonitorValueDeregister( + subscriptions, + parameterListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test reception of a parameter value update + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // update BackendTimer with now + // now=1/1/2025 01:05:00 (ie +5:00) + System.out.println("skip time to 1/1/2025 01:05:00"); + timer.skip(5*60*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=12.00, convertedValue=null} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new Union(new Double(12.00)), + null)); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * test a simple setValue/getValue sequence + * Requires previous execution of Test Case 1. + */ + @Test + public void testCase_02() { + // additional statement for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // update BackendTimer with now + // now=1/1/2025 01:06:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 01:06:00"); + timer.skip(1*60*1000); + + // call setValue with setValueParams + // setValueParams= + // - domain=null + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // - newRawValues={13.00} + execAndCheckSetValue( + null, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_1300))), + parameterListener, + startTime + TIMEOUT); + + // call getValue with getValueParams + // getValueParams= + // - domain=null + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1VOLTAGE", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=13.00, convertedValue=null} + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterBasicDataset.sat1Mtq1VoltageRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new Union(new Double(13.00)), + null))))); + execAndCheckGetValue( + null, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * test a user set value in an update + * Requires previous execution of Test Case 2. + */ + @Test + public void testCase_03() { + // additional statement for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // update BackendTimer with now + // now=1/1/2025 01:10:00 (ie +4:00) + System.out.println("skip time to 1/1/2025 01:10:00"); + timer.skip(4*60*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription with domain="fr.cnes.mission.sat1" and keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=13.00, convertedValue=null} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new Union(new Double(13.00)), + null)); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_2_Nominal_Values_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_2_Nominal_Values_Test.java new file mode 100755 index 000000000..091cab68d --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_2_Nominal_Values_Test.java @@ -0,0 +1,375 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.ParameterListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterDefaultDataset; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * PA_2_Nominal_Values_Test implements the test scenario #PA-2. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PA_2_Nominal_Values_Test extends ParameterTestClient { + + static ParameterListener parameterListener = new ParameterListener(); + static Identifier subscriptionId; + + // initialize BackendTimer with timeOrigin + // timeOrigin=1/1/2025 02:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 2, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterDefaultDataset backend = new ParameterDefaultDataset(timer); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(PA_2_Nominal_Values_Test.class.getName())); + setUp.setUp(null, null, null, null, backend, + false, false, false, false, true); + parameterConsumerStub = setUp.getParameterConsumer(); + + // call monitorValue.register with subscription + // subscription= + // - subscriptionId=21 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("21"); + execAndCheckMonitorValueRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + parameterListener, + System.currentTimeMillis() + TIMEOUT); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + PA_2_Nominal_Values_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + parameterListener.reset(); + execAndCheckMonitorValueDeregister( + subscriptions, + parameterListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test the nominal case for a parameter value monitoring + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // update BackendTimer with now + // now=1/1/2025 02:10:00 (ie +10:00) + System.out.println("skip time to 1/1/2025 02:10:00"); + timer.skip(10*60*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 2 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1" and keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=12.04, convertedValue=null} + // - timestamp=?, newValue={validityState=VALID, rawValue=12.05, convertedValue=null} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[2]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new Union(new Double(12.04)), + null)); + targetUpdates[1] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new Union(new Double(12.05)), + null)); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * test the nominal case for a parameter getValue + * Requires previous execution of Test Case 1. + */ + @Test + public void testCase_02() { + // additional statement for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // update BackendTimer with now + // now=1/1/2025 02:11:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 02:11:00"); + timer.skip(1*60*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // -- paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1VOLTAGE", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=12.08, convertedValue=null} + // -- paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=1, convertedValue="ENABLED"} + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1VoltageRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new Union(new Double(12.08)), + null)), + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new UInteger(1), + NA_STRING_ENABLED.getValue()))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // check no new message from subscription + waitAndCheckNoUpdate(parameterListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * test with a missing domain + * Requires previous execution of Test Case 2. + */ + @Test + public void testCase_03() { + // additional statement for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // call getValue with getValueParams + // getValueParams= + // - domain=null + // - keys={"ATT_BC_MTQ1ENABLED"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=1, convertedValue="ENABLED"} + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new UInteger(1), + NA_STRING_ENABLED.getValue()))))); + execAndCheckGetValue( + null, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 4. + * test the nominal case for a parameter setValue + * Requires previous execution of Test Case 3. + */ + @Test + public void testCase_04() { + // additional statement for dependent tests + TestDependency.before(3, this, "testCase_03", 4); + + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // update BackendTimer with now-1 + // now-1=1/1/2025 02:12:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 02:12:00"); + timer.skip(1*60*1000); + + // call setValue with setValueParams + // setValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // - newRawValues={13.04, 1} + execAndCheckSetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_1304, + NA_UINT_1))), + parameterListener, + startTime + TIMEOUT); + + // check no new message from subscription + waitAndCheckNoUpdate(parameterListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // -- paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1VOLTAGE", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=13.04, convertedValue=null} + // -- paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=1, convertedValue="ENABLED"} + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1VoltageRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1304.getValue(), + null)), + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_UINT_1.getValue(), + NA_STRING_ENABLED.getValue()))))); + parameterListener.reset(); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // check no new message from subscription + waitAndCheckNoUpdate(parameterListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // update BackendTimer with now-2 + // now-2=1/1/2025 02:15:00 (ie +3:00) + parameterListener.reset(); + System.out.println("skip time to 1/1/2025 02:15:00"); + timer.skip(3*60*1000); + + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" and keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=13.04, convertedValue=null} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1304.getValue(), + null)); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_3_Report_Config_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_3_Report_Config_Test.java new file mode 100755 index 000000000..112ca4c31 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_3_Report_Config_Test.java @@ -0,0 +1,751 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.ParameterListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterDatasetForReportConfig; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * PA_3_Report_Config_Test implements the test scenario #PA-3. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PA_3_Report_Config_Test extends ParameterTestClient { + + static ParameterListener parameterListener = new ParameterListener(); + static Identifier subscriptionId; + + // initialize BackendTimer with timeOrigin + // timeOrigin=1/1/2025 03:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 3, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterDatasetForReportConfig backend = new ParameterDatasetForReportConfig(timer); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(PA_3_Report_Config_Test.class.getName())); + setUp.setUp(null, null, null, null, backend, + false, false, false, false, true); + parameterConsumerStub = setUp.getParameterConsumer(); + long startTime = System.currentTimeMillis(); + + // call monitorValue.register with subscription + // subscription= + // - subscriptionId=31 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("31"); + execAndCheckMonitorValueRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + parameterListener, + startTime + TIMEOUT); + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + PA_3_Report_Config_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + parameterListener.reset(); + execAndCheckMonitorValueDeregister( + subscriptions, + parameterListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test the nominal case for a parameter getReportingConfiguration + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=300s} + // - {reportingEnabled=false, reportInterval=300s} + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_300), + new ReportConfiguration( + false, + DURATION_300)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * test the nominal case for a parameter enableReporting + * Requires previous execution of Test Case 1. + */ + @Test + public void testCase_02() { + // additional statement for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // update BackendTimer with now1 + // now1=1/1/2025 03:01:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 03:01:00"); + timer.skip(1*60*1000); + + // check no new message from subscription + waitAndCheckNoUpdate(parameterListener, startTime + NOUPDATE_TIMEOUT); + + // call enableReporting with enableReportParams + // enableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + parameterListener.reset(); + execAndCheckEnableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" and keys={parameterKey="ATT_BC_MTQ1ENABLED", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=1, convertedValue="ENABLED"} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1ENABLED, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_UINT_1.getValue(), + NA_STRING_ENABLED.getValue())); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=300s} + // - {reportingEnabled=true, reportInterval=300s} + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<>(Arrays.asList( + new ReportConfiguration( + true, + DURATION_300), + new ReportConfiguration( + true, + DURATION_300)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + parameterListener.reset(); + // update BackendTimer with now2 + // now2=1/1/2025 03:05:00 (ie +4:00) + System.out.println("skip time to 1/1/2025 03:05:00"); + timer.skip(4*60*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=12.00, convertedValue=null} + targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1200.getValue(), + null)); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * test the nominal case for a parameter enableReporting + * Requires previous execution of Test Case 2. + */ + @Test + public void testCase_03() { + // additional statement for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // call disableReporting with disableReportParams + // disableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1ENABLED"} + execAndCheckDisableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=300s} + // - {reportingEnabled=false, reportInterval=300s} + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_300), + new ReportConfiguration( + false, + DURATION_300)))); + parameterListener.reset(); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 03:10:00 (ie +5:00) + parameterListener.reset(); + System.out.println("skip time to 1/1/2025 03:10:00"); + timer.skip(5*60*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" and keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=12.05, convertedValue=null} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1205.getValue(), + null)); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 4. + * test disableReporting with null keys + * Requires previous execution of Test Case 3. + */ + @Test + public void testCase_04() { + // additional statement for dependent tests + TestDependency.before(3, this, "testCase_03", 4); + + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // call disableReporting with disableReportParams + // disableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + execAndCheckDisableReporting( + Constant.DOMAIN_SAT1, + null, + parameterListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // - {reportingEnabled=false, reportInterval=300s} + // - {reportingEnabled=false, reportInterval=300s} + ReportConfigurationList expected = new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + false, + DURATION_300), + new ReportConfiguration( + false, + DURATION_300)))); + parameterListener.reset(); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 03:11:00 (ie +1:00) + parameterListener.reset(); + System.out.println("skip time to 1/1/2025 03:11:00"); + timer.skip(1*60*1000); + + // check no new message from subscription + waitAndCheckNoUpdate(parameterListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 5. + * test enableReporting with null keys + * Requires previous execution of Test Case 4. + */ + @Test + public void testCase_05() { + // additional statement for dependent tests + TestDependency.before(4, this, "testCase_04", 5); + + System.out.println("Running: testCase_05()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // call enableReporting with enableReportParams + // enableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + execAndCheckEnableReporting( + Constant.DOMAIN_SAT1, + null, + parameterListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 2 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1", order not relevant, + // 1 with keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=12.10, convertedValue=null} + // 1 with keys={parameterKey="ATT_BC_MTQ1ENABLED", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=1, convertedValue="ENABLED"} + MonitorValueUpdate[][] targetUpdates = new MonitorValueUpdate[2][]; + targetUpdates[0] = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1210.getValue(), + null)) + }; + targetUpdates[1] = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1ENABLED, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new UInteger(1), + NA_STRING_ENABLED.getValue())) + }; + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=300s} + // - {reportingEnabled=true, reportInterval=300s} + ReportConfigurationList expected = new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_300), + new ReportConfiguration( + true, + DURATION_300)))); + parameterListener.reset(); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now + // now=1/1/2025 03:15:00 (ie +4:00) + parameterListener.reset(); + System.out.println("skip time to 1/1/2025 03:15:00"); + timer.skip(4*60*1000); + + // check no new message from subscription + waitAndCheckNoUpdate(parameterListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 6. + * test the nominal case for a parameter setReportingPeriod + * Requires previous execution of Test Case 5. + */ + @Test + public void testCase_06() { + // additional statement for dependent tests + TestDependency.before(5, this, "testCase_05", 6); + + System.out.println("Running: testCase_06()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // call setReportingPeriod with setReportParams + // setReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // - reportInterval=600s + execAndCheckSetReportingPeriod( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + DURATION_600, + parameterListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=600s} + // - {reportingEnabled=true, reportInterval=300s} + ReportConfigurationList expected = new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_600), + new ReportConfiguration( + true, + DURATION_300)))); + parameterListener.reset(); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now1 + // now1=1/1/2025 03:20:00 (ie +5:00) + parameterListener.reset(); + System.out.println("skip time to 1/1/2025 03:20:00"); + timer.skip(5*60*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={parameterKey="ATT_BC_MTQ1ENABLED", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=1, convertedValue="ENABLED"} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1ENABLED, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new UInteger(1), + NA_STRING_ENABLED.getValue())); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // update BackendTimer with now2 + // now2=1/1/2025 03:21:00 (ie +1:00) + parameterListener.reset(); + System.out.println("skip time to 1/1/2025 03:21:00"); + timer.skip(1*60*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 2 NOTIFY messages from subscription + // with domain="fr.cnes.mission.sat1", order not relevant, + // 1 with keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=12.20, convertedValue=null} + // 1 with keys={parameterKey="ATT_BC_MTQ1ENABLED", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=1, convertedValue="ENABLED"} + MonitorValueUpdate[][] targetUpdates2 = new MonitorValueUpdate[2][]; + targetUpdates2[0] = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1220.getValue(), + null)) + }; + targetUpdates2[1] = new MonitorValueUpdate[] { + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1ENABLED, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + new UInteger(1), + NA_STRING_ENABLED.getValue())) + }; + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates2); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 7. + * test setReportingPeriod with value 0 + * Requires previous execution of Test Case 6. + */ + @Test + public void testCase_07() { + // additional statement for dependent tests + TestDependency.before(6, this, "testCase_06", 7); + + System.out.println("Running: testCase_07()"); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // call disableReporting with disableReportParams + // disableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE"} + execAndCheckDisableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + parameterListener, + startTime + TIMEOUT); + + // call setReportingPeriod with setReportParams + // setReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // - reportInterval=0s + execAndCheckSetReportingPeriod( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + DURATION_0, + parameterListener, + startTime + TIMEOUT); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // - {reportingEnabled=false, reportInterval=60s} + // - {reportingEnabled=true, reportInterval=300s} + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + false, + DURATION_60), + new ReportConfiguration( + true, + DURATION_300)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // update BackendTimer with now1 + // now1=1/1/2025 03:22:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 03:22:00"); + timer.skip(1*60*1000); + + // check no new message from subscription + waitAndCheckNoUpdate(parameterListener, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + + // call enableReporting with enableReportParams + // enableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys=null + parameterListener.reset(); + execAndCheckEnableReporting( + Constant.DOMAIN_SAT1, + null, + parameterListener, + startTime + TIMEOUT); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=12:20, convertedValue=null} + MonitorValueUpdate[] targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1220.getValue(), + null)); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // update BackendTimer with now2 + // now2=1/1/2025 03:23:00 (ie +1:00) + parameterListener.reset(); + System.out.println("skip time to 1/1/2025 03:23:00"); + timer.skip(1*60*1000); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY message from subscription + // with domain="fr.cnes.mission.sat1" + // and keys={parameterKey="ATT_BC_MTQ1VOLTAGE", parameterVersion=1}: + // - timestamp=?, newValue={validityState=VALID, rawValue=12:20, convertedValue=null} + targetUpdates = new MonitorValueUpdate[1]; + targetUpdates[0] = + new MonitorValueUpdate( + Constant.DOMAIN_SAT1, + Constant.ID_MTQ1VOLTAGE, + new UInteger(1), + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1220.getValue(), + null)); + waitAndCheckForUpdates(parameterListener, startTime + TIMEOUT, targetUpdates); + + // additional statement for dependent tests + TestDependency.after(); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_4_Validity_State_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_4_Validity_State_Test.java new file mode 100755 index 000000000..1a2d9dffa --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_4_Validity_State_Test.java @@ -0,0 +1,428 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.ParameterListener.MonitorValueUpdate; +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterDatasetForReportConfig; +import org.ccsds.mo.mc.testbed.backends.ParameterDatasetForValidityState; +import org.ccsds.mo.mc.testbed.backends.ParameterDefaultDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * PA_4_Validity_State_Test implements the test scenario #PA-4. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PA_4_Validity_State_Test extends ParameterTestClient { + + static ParameterListener parameterListener = new ParameterListener(); + static Identifier subscriptionId; + + // initialize BackendTimer with timeOrigin + // timeOrigin=1/1/2025 04:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 4, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterDatasetForValidityState backend = new ParameterDatasetForValidityState(timer); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(PA_4_Validity_State_Test.class.getName())); + setUp.setUp(null, null, null, null, backend, + false, false, false, false, true); + parameterConsumerStub = setUp.getParameterConsumer(); + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + PA_4_Validity_State_Test.class.getName() + " tearDownClass()"); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test state INVALID_RAW + */ + @Test + public void testCase_01() { + // additional statement for dependent tests + TestDependency.reset(); + TestDependency.before(0, this, null, 1); + + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + // update BackendTimer with now + // now=1/1/2025 04:01:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 04:01:00"); + timer.skip(1*60*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1ENABLED"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=INVALID_RAW, rawValue=null, convertedValue=null} + parameterListener.reset(); + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.INVALID_RAW, + null, + null))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 2. + * test state VALID + * Requires previous execution of Test Case 1. + */ + @Test + public void testCase_02() { + // additional statement for dependent tests + TestDependency.before(1, this, "testCase_01", 2); + + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + // update BackendTimer with now + // now=1/1/2025 04:02:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 04:02:00"); + timer.skip(1*60*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1ENABLED"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=1, convertedValue="ENABLED"} + parameterListener.reset(); + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_UINT_1.getValue(), + NA_STRING_ENABLED.getValue()))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 3. + * test state EXPIRED + * Requires previous execution of Test Case 2. + */ + @Test + public void testCase_03() { + // additional statement for dependent tests + TestDependency.before(2, this, "testCase_02", 3); + + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + // update BackendTimer with now + // now=1/1/2025 04:13:00 (ie +11:00) + System.out.println("skip time to 1/1/2025 04:13:00"); + timer.skip(11*60*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1ENABLED"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=EXPIRED, rawValue=1, convertedValue="ENABLED"} + parameterListener.reset(); + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.EXPIRED, + NA_UINT_1.getValue(), + NA_STRING_ENABLED.getValue()))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 4. + * test state INVALID + * Requires previous execution of Test Case 3. + */ + @Test + public void testCase_04() { + // additional statement for dependent tests + TestDependency.before(3, this, "testCase_03", 4); + + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + // update BackendTimer with now + // now=1/1/2025 04:14:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 04:14:00"); + timer.skip(1*60*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1ENABLED"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=INVALID, rawValue=-1, convertedValue="UNKNOWN"} + parameterListener.reset(); + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.INVALID, + NA_UINT_8.getValue(), + NA_STRING_UNKNOWN.getValue()))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 5. + * test INVALID EXPIRED combination + * Requires previous execution of Test Case 4. + */ + @Test + public void testCase_05() { + // additional statement for dependent tests + TestDependency.before(4, this, "testCase_04", 5); + + System.out.println("Running: testCase_05()"); + long startTime = System.currentTimeMillis(); + + // update BackendTimer with now + // now=1/1/2025 04:25:00 (ie +11:00) + System.out.println("skip time to 1/1/2025 04:25:00"); + timer.skip(11*60*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1ENABLED"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=INVALID, rawValue=-1, convertedValue="UNKNOWN"} + parameterListener.reset(); + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.INVALID, + NA_UINT_8.getValue(), + NA_STRING_UNKNOWN.getValue()))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 6. + * test state INVALID_CONVERSION + * Requires previous execution of Test Case 5. + */ + @Test + public void testCase_06() { + // additional statement for dependent tests + TestDependency.before(5, this, "testCase_05", 6); + + System.out.println("Running: testCase_06()"); + long startTime = System.currentTimeMillis(); + + // update BackendTimer with now + // now=1/1/2025 04:26:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 04:26:00"); + timer.skip(1*60*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1ENABLED"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=INVALID_CONVERSION, rawValue=2, convertedValue=null} + parameterListener.reset(); + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.INVALID_CONVERSION, + NA_UINT_2.getValue(), + null))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + + /** + * Test Case 7. + * test INVALID_CONVERSION EXPIRED combination + * Requires previous execution of Test Case 6. + */ + @Test + public void testCase_07() { + // additional statement for dependent tests + TestDependency.before(6, this, "testCase_06", 7); + + System.out.println("Running: testCase_07()"); + long startTime = System.currentTimeMillis(); + + // update BackendTimer with now + // now=1/1/2025 04:37:00 (ie +11:00) + System.out.println("skip time to 1/1/2025 04:37:00"); + timer.skip(11*60*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1ENABLED"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=INVALID_CONVERSION, rawValue=2, convertedValue=null} + parameterListener.reset(); + ParameterValueList expected = new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterDefaultDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.INVALID_CONVERSION, + NA_UINT_2.getValue(), + null))))); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + // additional statement for dependent tests + TestDependency.after(); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_9_Errors_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_9_Errors_Test.java new file mode 100755 index 000000000..9e356ec6f --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PA_9_Errors_Test.java @@ -0,0 +1,522 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.ParameterErrorDataset; +import org.ccsds.moims.mo.mal.MALHelper; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mc.MCHelper; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * PA_9_Errors_Test implements the test scenario #PA-9. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PA_9_Errors_Test extends ParameterTestClient { + + static ParameterListener parameterListener = new ParameterListener(); + static Identifier subscriptionId; + + // initialize BackendTimer with timeOrigin + // timeOrigin=1/1/2025 09:00:00 + private static final LocalDateTime testOrigin = LocalDateTime.of(2025, 1, 1, 9, 0, 0); + private static long now = testOrigin.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(testOrigin))*1000; + private static final BackendTimerImpl timer = new BackendTimerImpl(now); + private static final ParameterErrorDataset backend = new ParameterErrorDataset(timer); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(PA_9_Errors_Test.class.getName())); + setUp.setUp(null, null, null, null, backend, + false, false, false, false, true); + parameterConsumerStub = setUp.getParameterConsumer(); + long startTime = System.currentTimeMillis(); + + parameterListener.reset(); + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // - {reportingEnabled=true, reportInterval=300s} + // - {reportingEnabled=false, reportInterval=300s} + ReportConfigurationList expected = + new ReportConfigurationList(new ArrayList<> (Arrays.asList( + new ReportConfiguration( + true, + DURATION_300), + new ReportConfiguration( + false, + DURATION_300)))); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + expected); + + parameterListener.reset(); + // update BackendTimer with now + // now=1/1/2025 09:01:00 (ie +1:00) + System.out.println("skip time to 1/1/2025 09:01:00"); + timer.skip(1*60*1000); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check response as list of 2 items: + // -- paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1VOLTAGE", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=12.00, convertedValue=null} + // -- paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1ENABLED", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=1, convertedValue="ENABLED"} + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterErrorDataset.sat1Mtq1VoltageRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1200.getValue(), + null)), + new ParameterValue( + ParameterErrorDataset.sat1Mtq1EnabledRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_UINT_1.getValue(), + NA_STRING_ENABLED.getValue())))))); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + PA_9_Errors_Test.class.getName() + " tearDownClass()"); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + * test ambiguity with a null domain + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + long startTime = System.currentTimeMillis(); + + // call getValue with getValueParams + // getValueParams= + // - domain=null + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check ERROR message with code Ambiguous + // check the extraInfo field as a singleton list holding element 0 + parameterListener.reset(); + execAndCheckErrorGetValue( + null, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + MCHelper.AMBIGUOUS_ERROR_NUMBER, + EXTRA_UIL_0); + + } + + /** + * Test Case 2. + * test unknown parameter + */ + @Test + public void testCase_02() { + System.out.println("Running: testCase_02()"); + long startTime = System.currentTimeMillis(); + + // call getValue with getValueParams + // getValueParams= + // - domain=domain="fr.cnes.mission.sat2" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 1 + parameterListener.reset(); + execAndCheckErrorGetValue( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_1); + + } + + /** + * Test Case 3. + * test inconsistent parameters + */ + @Test + public void testCase_03() { + System.out.println("Running: testCase_03()"); + long startTime = System.currentTimeMillis(); + + // call setValue with setValueParams + // setValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // - newRawValues={19.03, 1} + // check ERROR message with code Invalid + // check the extraInfo field as a singleton list holding element 1 + parameterListener.reset(); + execAndCheckErrorSetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_1903, + NA_UINT_1))), + parameterListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + EXTRA_UIL_1); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1VOLTAGE", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=12.00, convertedValue=null} + parameterListener.reset(); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + parameterListener, + startTime + TIMEOUT, + new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterErrorDataset.sat1Mtq1VoltageRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1200.getValue(), + null)))))); + + } + + /** + * Test Case 4. + * test setting a read only parameter + */ + @Test + public void testCase_04() { + System.out.println("Running: testCase_04()"); + long startTime = System.currentTimeMillis(); + + // call setValue with setValueParams + // setValueParams= + // - domain="fr.cnes.mission.sat2" + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // - newRawValues={19.04} + // check ERROR message with code Read Only + // check the extraInfo field as a singleton list holding element 0 + parameterListener.reset(); + execAndCheckErrorSetValue( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_1904))), + parameterListener, + startTime + TIMEOUT, + MCHelper.READ_ONLY_ERROR_NUMBER, + EXTRA_UIL_0); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat2" + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat2", "ATT_BC_MTQ1VOLTAGE", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=22.00, convertedValue=null} + parameterListener.reset(); + execAndCheckGetValue( + Constant.DOMAIN_SAT2, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + parameterListener, + startTime + TIMEOUT, + new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterErrorDataset.sat2Mtq1VoltageRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_2200.getValue(), + null)))))); + + } + + /** + * Test Case 5. + * test invalid value type + */ + @Test + public void testCase_05() { + System.out.println("Running: testCase_05()"); + long startTime = System.currentTimeMillis(); + + // call setValue with setValueParams + // setValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // - newRawValues={19.05, "DISABLED"} + // check ERROR message with code Invalid + // check the extraInfo field as a singleton list holding element 1 + parameterListener.reset(); + execAndCheckErrorSetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_DOUBLE_1905, + NA_STRING_DISABLED))), + parameterListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + EXTRA_UIL_1); + + // call getValue with getValueParams + // getValueParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // check response as singleton list: + // - paramRef={"fr.cnes.mission.sat1", "ATT_BC_MTQ1VOLTAGE", version=1} + // - timestamp=? + // - value={validityState=VALID, rawValue=12.00, convertedValue=null} + parameterListener.reset(); + execAndCheckGetValue( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + parameterListener, + startTime + TIMEOUT, + new ParameterValueList(new ArrayList<> (Arrays.asList( + new ParameterValue( + ParameterErrorDataset.sat1Mtq1VoltageRef, + null, // timestamp, unchecked + null, // samplingTime, unchecked + new ParameterValueData( + ValidityState.VALID, + NA_DOUBLE_1200.getValue(), + null)))))); + + } + + /** + * Test Case 6. + * test atomicity of enableReporting operation + */ + @Test + public void testCase_06() { + System.out.println("Running: testCase_06()"); + long startTime = System.currentTimeMillis(); + + // call enableReporting with enableReportParams + // enableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"UNKNOWN", "ATT_BC_MTQ1ENABLED"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 0 + parameterListener.reset(); + execAndCheckErrorEnableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_UNKNOWN, + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_0); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1ENABLED"} + // check response as a singleton list: + // - {reportingEnabled=false, reportInterval=300s} + parameterListener.reset(); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1ENABLED))), + parameterListener, + startTime + TIMEOUT, + new ReportConfigurationList(new ArrayList<>(Arrays.asList( + new ReportConfiguration( + false, + DURATION_300))))); + + } + + /** + * Test Case 7. + * test atomicity of disableReporting operation + */ + @Test + public void testCase_07() { + System.out.println("Running: testCase_07()"); + long startTime = System.currentTimeMillis(); + + // call disableReporting with disableReportParams + // disableReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "UNKNOWN"} + // check ERROR message with code Unknown + // check the extraInfo field as a singleton list holding element 1 + parameterListener.reset(); + execAndCheckErrorDisableReporting( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_UNKNOWN))), + parameterListener, + startTime + TIMEOUT, + MALHelper.UNKNOWN_ERROR_NUMBER, + EXTRA_UIL_1); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // check response as a singleton list: + // - {reportingEnabled=true, reportInterval=300s} + parameterListener.reset(); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + parameterListener, + startTime + TIMEOUT, + new ReportConfigurationList(new ArrayList<>(Arrays.asList( + new ReportConfiguration( + true, + DURATION_300))))); + + } + + /** + * Test Case 8. + * test atomicity of setReportingPeriod operation + */ + @Test + public void testCase_08() { + System.out.println("Running: testCase_07()"); + long startTime = System.currentTimeMillis(); + + // call setReportingPeriod with setReportParams + // setReportParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE", "ATT_BC_MTQ1ENABLED"} + // - reportInterval=60s + // check ERROR message with code Invalid + // check the extraInfo field as a singleton list holding element 1 + parameterListener.reset(); + execAndCheckErrorSetReportingPeriod( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE, + Constant.ID_MTQ1ENABLED))), + DURATION_60, + parameterListener, + startTime + TIMEOUT, + MCHelper.INVALID_ERROR_NUMBER, + EXTRA_UIL_1); + + // call getReportingConfiguration with getReportConfigParams + // getReportConfigParams= + // - domain="fr.cnes.mission.sat1" + // - keys={"ATT_BC_MTQ1VOLTAGE"} + // check response as a singleton list: + // - {reportingEnabled=true, reportInterval=300s} + parameterListener.reset(); + execAndCheckGetReportingConfiguration( + Constant.DOMAIN_SAT1, + new IdentifierList(new ArrayList<> (Arrays.asList( + Constant.ID_MTQ1VOLTAGE))), + parameterListener, + startTime + TIMEOUT, + new ReportConfigurationList(new ArrayList<>(Arrays.asList( + new ReportConfiguration( + true, + DURATION_300))))); + + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PK_1_Basic_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PK_1_Basic_Test.java new file mode 100755 index 000000000..55e45e394 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PK_1_Basic_Test.java @@ -0,0 +1,168 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.PacketBasicDataset; +import org.ccsds.mo.mc.testbed.AlertListener.MonitorAlertUpdate; +import org.ccsds.mo.mc.testbed.PacketListener.DeliverPacketUpdate; +import org.ccsds.mo.mc.testbed.backends.AlertBasicDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Blob; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UOctet; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.alert.consumer.AlertAdapter; +import org.ccsds.moims.mo.mc.structures.AlertDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.Severity; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PK_1_Basic_Test extends PacketTestClient { + + static PacketListener packetListener = new PacketListener(); + static Identifier subscriptionId; + + private static final PacketBasicDataset backend = new PacketBasicDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(PK_1_Basic_Test.class.getName())); + setUp.setUp(null, null, null, backend, null, + false, false, false, true, false); + packetConsumerStub = setUp.getPacketConsumer(); + + // call deliverPacket.register with subscription + // subscription= + // - subscriptionId=11 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId = new Identifier("11"); + execAndCheckDeliverPacketRegister( + new Subscription(subscriptionId, + Constant.DOMAIN_WILDCARD, + null, null), + packetListener, + System.currentTimeMillis() + TIMEOUT); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + PK_1_Basic_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId); + packetListener.reset(); + execAndCheckDeliverPacketDeregister( + subscriptions, + packetListener, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + + long startTime = System.currentTimeMillis(); + // call backend.publishPacket with testPacket + // testPacket= + // - domain="fr.cnes.mission.sat1" + // - keys={apid=3, destID=11} + // - spacePacket: first byte=0, length=20 + packetListener.reset(); + NullableAttributeList packetKeys = + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_USHORT_3, NA_UOCTET_11))); + byte testPacketFirstByte = (byte) 0; + Blob testPacket = new Blob(generateTestPacket(20, testPacketFirstByte)); + backend.publishPacket( + Constant.DOMAIN_SAT1, + packetKeys, + new Time(System.currentTimeMillis()), + testPacket); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription + // with testPacket values + DeliverPacketUpdate[] targetUpdates = new DeliverPacketUpdate[1]; + targetUpdates[0] = + new DeliverPacketUpdate( + Constant.DOMAIN_SAT1, + US_3, + UO_11, + null, // timestamp, unchecked + testPacket); + waitAndCheckForUpdates( + packetListener, + startTime + TIMEOUT, + targetUpdates); + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PK_2_Extended_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PK_2_Extended_Test.java new file mode 100755 index 000000000..c07f73926 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PK_2_Extended_Test.java @@ -0,0 +1,381 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Logger; + +import org.ccsds.mo.mc.testbed.backends.BackendTimerImpl; +import org.ccsds.mo.mc.testbed.backends.PacketBasicDataset; +import org.ccsds.mo.mc.testbed.AlertListener.MonitorAlertUpdate; +import org.ccsds.mo.mc.testbed.PacketListener.DeliverPacketUpdate; +import org.ccsds.mo.mc.testbed.backends.AlertBasicDataset; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.AttributeList; +import org.ccsds.moims.mo.mal.structures.Blob; +import org.ccsds.moims.mo.mal.structures.Element; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttribute; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.SubscriptionFilter; +import org.ccsds.moims.mo.mal.structures.SubscriptionFilterList; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UOctet; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mal.structures.Union; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.alert.consumer.AlertAdapter; +import org.ccsds.moims.mo.mc.structures.AlertDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.Severity; +import org.ccsds.moims.mo.mc.structures.ValidityState; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PK_2_Extended_Test extends PacketTestClient { + + static PacketListener packetListener1 = new PacketListener(); + static PacketListener packetListener2 = new PacketListener(); + static Identifier subscriptionId1; + static Identifier subscriptionId2; + + private static final PacketBasicDataset backend = new PacketBasicDataset(); + + @BeforeClass + public static void setUpClass() throws IOException { + System.out.println(TEST_SET_UP_CLASS_1); + System.out.println(TEST_SET_UP_CLASS_2); + setUnitTestLogger(Logger.getLogger(PK_2_Extended_Test.class.getName())); + setUp.setUp(null, null, null, backend, null, + false, false, false, true, false); + packetConsumerStub = setUp.getPacketConsumer(); + + // call deliverPacket.register with subscription-1 + // subscription-1= + // - subscriptionId=21 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters=null + subscriptionId1 = new Identifier("21"); + execAndCheckDeliverPacketRegister( + new Subscription(subscriptionId1, + Constant.DOMAIN_WILDCARD, + null, null), + packetListener1, + System.currentTimeMillis() + TIMEOUT); + + // call deliverPacket.register with subscription-2 + // subscription-2= + // - subscriptionId=22 + // - domain="fr.cnes.mission.*" + // - selectedKeys=null + // - filters={{name="apid", values={3}}, {name="destID", values={11}}} + subscriptionId2 = new Identifier("22"); + execAndCheckDeliverPacketRegister( + new Subscription(subscriptionId2, + Constant.DOMAIN_WILDCARD, + null, + new SubscriptionFilterList(new ArrayList(Arrays.asList( + new SubscriptionFilter( + Constant.ID_APID, + new AttributeList(NA_USHORT_3.getValue())), + new SubscriptionFilter( + Constant.ID_DESTID, + new AttributeList(NA_UOCTET_11.getValue())))))), + packetListener2, + System.currentTimeMillis() + TIMEOUT); + + } + + @AfterClass + public static void tearDownClass() { + System.out.println("Entered: " + PK_2_Extended_Test.class.getName() + " tearDownClass()"); + + IdentifierList subscriptions = new IdentifierList(); + subscriptions.add(subscriptionId1); + subscriptions.add(subscriptionId2); + packetListener1.reset(); + execAndCheckDeliverPacketDeregister( + subscriptions, + packetListener1, + System.currentTimeMillis() + TIMEOUT); + + MCTest.tearDownClass(); + } + + /** + * Test Case 1. + */ + @Test + public void testCase_01() { + System.out.println("Running: testCase_01()"); + + long startTime = System.currentTimeMillis(); + // call backend.publishPacket with testPacket + // testPacket= + // - domain="fr.cnes.mission.sat1" + // - keys={apid=3, destID=11} + // - spacePacket: first byte=0, length=20 + packetListener1.reset(); + packetListener2.reset(); + byte testPacketFirstByte = (byte) 0; + Blob testPacket = new Blob(generateTestPacket(20, testPacketFirstByte)); + backend.publishPacket( + Constant.DOMAIN_SAT1, + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_USHORT_3, NA_UOCTET_11))), + new Time(System.currentTimeMillis()), + testPacket); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription-1 and subscription-2 + // with testPacket values + DeliverPacketUpdate[] targetUpdates = new DeliverPacketUpdate[1]; + targetUpdates[0] = + new DeliverPacketUpdate( + Constant.DOMAIN_SAT1, + US_3, + UO_11, + null, // timestamp, unchecked + testPacket); + waitAndCheckForUpdates( + packetListener1, + startTime + TIMEOUT, + targetUpdates); + waitAndCheckForUpdates( + packetListener2, + startTime + TIMEOUT, + targetUpdates); + } + + /** + * Test Case 2. + */ + @Test + public void testCase_02() { + System.out.println("Running: testCase_02()"); + + long startTime = System.currentTimeMillis(); + // call backend.publishPacket with testPacket + // testPacket= + // - domain="fr.cnes.mission.sat1" + // - keys={apid=4, destID=11} + // - spacePacket: first byte=1, length=20 + packetListener1.reset(); + packetListener2.reset(); + byte testPacketFirstByte = (byte) 1; + Blob testPacket = new Blob(generateTestPacket(20, testPacketFirstByte)); + backend.publishPacket( + Constant.DOMAIN_SAT1, + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_USHORT_4, NA_UOCTET_11))), + new Time(System.currentTimeMillis()), + testPacket); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription-1 + // with testPacket values + DeliverPacketUpdate[] targetUpdates = new DeliverPacketUpdate[1]; + targetUpdates[0] = + new DeliverPacketUpdate( + Constant.DOMAIN_SAT1, + US_4, + UO_11, + null, // timestamp, unchecked + testPacket); + waitAndCheckForUpdates( + packetListener1, + startTime + TIMEOUT, + targetUpdates); + + // check no new message from subscription-2 + waitAndCheckNoUpdate(packetListener2, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + } + + /** + * Test Case 3. + */ + @Test + public void testCase_03() { + System.out.println("Running: testCase_03()"); + + long startTime = System.currentTimeMillis(); + // call backend.publishPacket with testPacket + // testPacket= + // - domain="fr.cnes.mission.sat1" + // - keys={apid=3, destID=12} + // - spacePacket: first byte=2, length=20 + packetListener1.reset(); + packetListener2.reset(); + byte testPacketFirstByte = (byte) 2; + Blob testPacket = new Blob(generateTestPacket(20, testPacketFirstByte)); + backend.publishPacket( + Constant.DOMAIN_SAT1, + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_USHORT_3, NA_UOCTET_12))), + new Time(System.currentTimeMillis()), + testPacket); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription-1 + // with testPacket values + DeliverPacketUpdate[] targetUpdates = new DeliverPacketUpdate[1]; + targetUpdates[0] = + new DeliverPacketUpdate( + Constant.DOMAIN_SAT1, + US_3, + UO_12, + null, // timestamp, unchecked + testPacket); + waitAndCheckForUpdates( + packetListener1, + startTime + TIMEOUT, + targetUpdates); + + // check no new message from subscription-2 + waitAndCheckNoUpdate(packetListener2, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + } + + /** + * Test Case 4. + */ + @Test + public void testCase_04() { + System.out.println("Running: testCase_04()"); + + long startTime = System.currentTimeMillis(); + // call backend.publishPacket with testPacket + // testPacket= + // - domain="fr.cnes.mission.sat1" + // - keys={apid=3, destID=null} + // - spacePacket: first byte=3, length=20 + packetListener1.reset(); + packetListener2.reset(); + byte testPacketFirstByte = (byte) 3; + Blob testPacket = new Blob(generateTestPacket(20, testPacketFirstByte)); + backend.publishPacket( + Constant.DOMAIN_SAT1, + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_USHORT_3, NA_NULL))), + new Time(System.currentTimeMillis()), + testPacket); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription-1 + // with testPacket values + DeliverPacketUpdate[] targetUpdates = new DeliverPacketUpdate[1]; + targetUpdates[0] = + new DeliverPacketUpdate( + Constant.DOMAIN_SAT1, + US_3, + null, + null, // timestamp, unchecked + testPacket); + waitAndCheckForUpdates( + packetListener1, + startTime + TIMEOUT, + targetUpdates); + + // check no new message from subscription-2 + waitAndCheckNoUpdate(packetListener2, System.currentTimeMillis() + NOUPDATE_TIMEOUT); + } + + /** + * Test Case 5. + */ + @Test + public void testCase_05() { + System.out.println("Running: testCase_05()"); + + long startTime = System.currentTimeMillis(); + // call backend.publishPacket with testPacket + // testPacket= + // - domain="fr.cnes.mission.sat1" + // - keys={apid=3, destID=11} + // - spacePacket: first byte=4, length=65542 + packetListener1.reset(); + packetListener2.reset(); + byte testPacketFirstByte = (byte) 4; + Blob testPacket = new Blob(generateTestPacket(65542, testPacketFirstByte)); + backend.publishPacket( + Constant.DOMAIN_SAT1, + new NullableAttributeList(new ArrayList<> (Arrays.asList( + NA_USHORT_3, NA_UOCTET_11))), + new Time(System.currentTimeMillis()), + testPacket); + + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + // check reception of 1 NOTIFY messages from subscription-1 and subscription-2 + // with testPacket values + DeliverPacketUpdate[] targetUpdates = new DeliverPacketUpdate[1]; + targetUpdates[0] = + new DeliverPacketUpdate( + Constant.DOMAIN_SAT1, + US_3, + UO_11, + null, // timestamp, unchecked + testPacket); + waitAndCheckForUpdates( + packetListener1, + startTime + TIMEOUT, + targetUpdates); + waitAndCheckForUpdates( + packetListener2, + startTime + TIMEOUT, + targetUpdates); + + } + +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PacketListener.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PacketListener.java new file mode 100755 index 000000000..02faaaa8d --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PacketListener.java @@ -0,0 +1,181 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Blob; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UOctet; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.packet.consumer.PacketAdapter; + +public class PacketListener extends PacketAdapter { + + static class DeliverPacketUpdate { + IdentifierList domain; + UShort apid; + UOctet destID; + Time timestamp; + Blob spacePacket; + public DeliverPacketUpdate( + IdentifierList domain, + UShort apid, + UOctet destID, + Time timestamp, + Blob spacePacket) { + this.domain = domain; + this.apid = apid; + this.destID = destID; + this.timestamp = timestamp; + this.spacePacket = spacePacket; + } + public String toString() { + StringBuilder out = new StringBuilder(); + out.append(this.getClass().getName()); + out.append("{domain=").append(domain); + out.append(", apid=").append(apid); + out.append(", destID=").append(destID); + out.append(", timestamp=").append(timestamp); + out.append(", spacePacket="); + if (spacePacket == null || spacePacket.getValue() == null) + out.append("null"); + else { + byte[] body = spacePacket.getValue(); + out.append("["); + if (body.length > 0) + out.append(body[0]).append(";"); + out.append(body.length).append("]"); + } + out.append("}"); + return out.toString(); + } + } + + String testException = null; + MOErrorException error = null; + boolean registerAckReceived = false; + boolean deregisterAckReceived = false; + ConcurrentLinkedQueue packetUpdates = new ConcurrentLinkedQueue<>(); + + synchronized void reset() { + testException = null; + error = null; + registerAckReceived = false; + deregisterAckReceived = false; + packetUpdates.clear(); + } + + public boolean hasError() { + return testException != null || error != null; + } + public String getError() { + if (error != null) + return error.toString(); + return testException; + } + + private void addTestException(String testException) { + if (this.testException == null) + this.testException = testException; + } + + @Override + public void deliverPacketRegisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: deliverPacketRegisterAckReceived()"); + synchronized(this) { + registerAckReceived = true; + notify(); + } + } + @Override + public void deliverPacketRegisterErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: deliverPacketRegisterErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void deliverPacketNotifyReceived( + MALMessageHeader msgHeader, + Identifier subscriptionId, + UpdateHeader updateHeader, + Time timestamp, + Blob spacePacket, + Map qosProperties) { + System.out.println("Reached: deliverPacketNotifyReceived() -> " + timestamp); + // all subscription keys are used in all the tests + NullableAttributeList keyValues = updateHeader.getKeyValues(); + UShort apid = null; + UOctet destID = null; + if (keyValues == null || keyValues.size() != 2) { + addTestException("Unexpected number of subscription key values"); + } else { + Attribute pApid = keyValues.get(0).getValue(); + if (pApid != null) + apid = (UShort) pApid; + Attribute pDestID = keyValues.get(1).getValue(); + if (pDestID != null) + destID = (UOctet) pDestID; + } + synchronized(this) { + packetUpdates.add(new DeliverPacketUpdate( + updateHeader.getDomain(), + apid, destID, + timestamp, spacePacket)); + notify(); + } + } + @Override + public void deliverPacketNotifyErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: deliverPacketNotifyErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void deliverPacketDeregisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: deliverPacketDeregisterAckReceived()"); + synchronized(this) { + deregisterAckReceived = true; + notify(); + } + } + +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PacketTestClient.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PacketTestClient.java new file mode 100755 index 000000000..64e90d1f2 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/PacketTestClient.java @@ -0,0 +1,230 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Random; + +import org.ccsds.mo.mc.testbed.PacketListener.DeliverPacketUpdate; +import org.ccsds.mo.mc.testbed.ParameterListener.MonitorValueUpdate; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.AttributeList; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mal.structures.UOctet; +import org.ccsds.moims.mo.mal.structures.UShort; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; + +import org.junit.Assert; + +/** +* This class provides shared functions for all Parameter test clients. +*/ +public class PacketTestClient extends MCTest { + + public static final Duration DURATION_0 = new Duration(0e0); + public static final Duration DURATION_60 = new Duration(60e3); + public static final Duration DURATION_300 = new Duration(300e3); + public static final Duration DURATION_600 = new Duration(600e3); + + public static final UShort US_3 = new UShort(3); + public static final UShort US_4 = new UShort(4); + public static final UOctet UO_11 = new UOctet(11); + public static final UOctet UO_12 = new UOctet(12); + + static final Random random = new Random(System.currentTimeMillis()); + byte[] generateTestPacket(int size, byte firstByte) { + byte[] result = new byte[size]; + random.nextBytes(result); + result[0] = firstByte; + return result; + } + protected static void execAndCheckDeliverPacketRegister( + Subscription subscription, + PacketListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + packetConsumerStub.asyncDeliverPacketRegister( + subscription, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.registerAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate it + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.registerAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckDeliverPacketDeregister( + IdentifierList subscriptions, + PacketListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + packetConsumerStub.asyncDeliverPacketDeregister( + subscriptions, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.deregisterAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate it + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.deregisterAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + /** + * Waits for expected updates and checks them. + * All updates relates to the same Parameter. + * + * @param listener callback listener + * @param maxTime max waiting time + * @param updates expected updates + */ + protected static void waitAndCheckForUpdates( + PacketListener listener, + long maxTime, + DeliverPacketUpdate[] updates) { + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + int nbUpdates = updates.length; + synchronized(listener) { + while (!listener.hasError() && + listener.packetUpdates.size() != nbUpdates && + timeout > 0) { + try { + System.out.println("wait for Updates from subscription"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + System.out.println("end wait, listener=" + listener); + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.packetUpdates.size() != nbUpdates) + unitTestFail("Incorrect number of updates received: " + + "expected " + nbUpdates + + " was " + listener.packetUpdates.size()); + // check received updates + Iterator it = listener.packetUpdates.iterator(); + for (int idx = 0; it.hasNext(); idx++) { + assertEquals("Update[" + idx + "]", updates[idx], it.next()); + } + } + } + + protected static void waitAndCheckNoUpdate( + PacketListener listener, + long maxTime) { + // ------------------------------------------------------------------------ + // Wait for TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + synchronized(listener) { + while (!listener.hasError() && + timeout > 0) { + try { + System.out.println("wait for timeout"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + + // check no new message from subscription + if (!listener.packetUpdates.isEmpty()) + unitTestFail("received unexpected updates"); + } + } + + protected static void assertEquals( + String error, + DeliverPacketUpdate expected, + DeliverPacketUpdate actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + ", expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + ", expecting " + expected + ", was " + actual); + Assert.assertEquals(error + " unexpected domain", expected.domain, actual.domain); + Assert.assertEquals(error + " unexpected apid", expected.apid, actual.apid); + Assert.assertEquals(error + " unexpected destID", expected.destID, actual.destID); + Assert.assertEquals(error + " unexpected spacePacket", expected.spacePacket, actual.spacePacket); + } +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ParameterListener.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ParameterListener.java new file mode 100755 index 000000000..4d9086dad --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ParameterListener.java @@ -0,0 +1,383 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.ccsds.moims.mo.mal.MOErrorException; +import org.ccsds.moims.mo.mal.structures.Attribute; +import org.ccsds.moims.mo.mal.structures.Identifier; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.Time; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UpdateHeader; +import org.ccsds.moims.mo.mal.transport.MALMessageHeader; +import org.ccsds.moims.mo.mc.parameter.consumer.ParameterAdapter; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; + +public class ParameterListener extends ParameterAdapter { + + static class MonitorValueUpdate { + IdentifierList domain; + Identifier parameterKey; + UInteger parameterVersion; + Time timestamp; + Time samplingTime; + ParameterValueData newValue; + public MonitorValueUpdate( + IdentifierList domain, + Identifier parameterKey, + UInteger parameterVersion, + Time timestamp, + Time samplingTime, + ParameterValueData newValue) { + this.domain = domain; + this.parameterKey = parameterKey; + this.parameterVersion = parameterVersion; + this.timestamp = timestamp; + this.samplingTime = samplingTime; + this.newValue = newValue; + } + public String toString() { + StringBuilder out = new StringBuilder(); + out.append(this.getClass().getName()); + out.append("{domain=").append(domain); + out.append(", parameterKey=").append(parameterKey); + out.append(", parameterVersion=").append(parameterVersion); + out.append(", timestamp=").append(timestamp); + out.append(", samplingTime=").append(samplingTime); + out.append(", newValue=").append(newValue); + out.append("}"); + return out.toString(); + } + } + + String testException = null; + MOErrorException error = null; + boolean setValueAckReceived = false; + boolean registerAckReceived = false; + boolean deregisterAckReceived = false; + ParameterValueList getValueResponse = null; + ConcurrentLinkedQueue valueUpdates = new ConcurrentLinkedQueue<>(); + ReportConfigurationList getReportConfigResponse = null; + boolean enableReportingAckReceived = false; + boolean disableReportingAckReceived = false; + boolean setReportingPeriodAckReceived = false; + + synchronized void reset() { + testException = null; + error = null; + setValueAckReceived = false; + registerAckReceived = false; + deregisterAckReceived = false; + getValueResponse = null; + valueUpdates.clear(); + getReportConfigResponse = null; + enableReportingAckReceived = false; + disableReportingAckReceived = false; + setReportingPeriodAckReceived = false; + } + + public String toString() { + StringBuilder out = new StringBuilder(); + String prefix=""; + out.append(this.getClass().getName()); + if (testException != null) { + out.append(prefix).append("testException=").append(testException); + prefix = ", "; + } + if (error != null) { + out.append(prefix).append("error=").append(error); + prefix = ", "; + } + if (setValueAckReceived) { + out.append(prefix).append("setValueAckReceived=").append(setValueAckReceived); + prefix = ", "; + } + if (registerAckReceived) { + out.append(prefix).append("registerAckReceived=").append(registerAckReceived); + prefix = ", "; + } + if (deregisterAckReceived) { + out.append(prefix).append("deregisterAckReceived=").append(deregisterAckReceived); + prefix = ", "; + } + if (getValueResponse != null) { + out.append(prefix).append("getValueResponse=").append(getValueResponse); + prefix = ", "; + } + if (valueUpdates != null) { + out.append(prefix).append("valueUpdates=").append(valueUpdates); + prefix = ", "; + } + if (getReportConfigResponse != null) { + out.append(prefix).append("getReportConfigResponse=").append(getReportConfigResponse); + prefix = ", "; + } + if (enableReportingAckReceived) { + out.append(prefix).append("enableReportingAckReceived=").append(enableReportingAckReceived); + prefix = ", "; + } + if (disableReportingAckReceived) { + out.append(prefix).append("disableReportingAckReceived=").append(disableReportingAckReceived); + prefix = ", "; + } + if (setReportingPeriodAckReceived) { + out.append(prefix).append("setReportingPeriodAckReceived=").append(setReportingPeriodAckReceived); + prefix = ", "; + } + out.append("}"); + return out.toString(); + } + + public boolean hasError() { + return testException != null || error != null; + } + public String getError() { + if (error != null) + return error.toString(); + return testException; + } + + private void addTestException(String testException) { + if (this.testException == null) + this.testException = testException; + } + + @Override + public void getValueResponseReceived( + MALMessageHeader msgHeader, + ParameterValueList parameterValues, + Map qosProperties) { + System.out.println("Reached: getValueResponseReceived()"); + if (parameterValues == null) { + // OUT field is not nullable + addTestException("getValue OUT parameter is null"); + } + synchronized(this) { + this.getValueResponse = parameterValues; + notify(); + } + } + @Override + public void getValueErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: getValueErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void setValueAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: setValueAckReceived()"); + synchronized(this) { + setValueAckReceived = true; + notify(); + } + } + @Override + public void setValueErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: setValueErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void monitorValueRegisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: monitorValueRegisterAckReceived()"); + synchronized(this) { + registerAckReceived = true; + notify(); + } + } + @Override + public void monitorValueRegisterErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: monitorValueRegisterErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void monitorValueNotifyReceived( + MALMessageHeader msgHeader, + Identifier subscriptionId, + UpdateHeader updateHeader, + Time timestamp, + Time samplingTime, + ParameterValueData newValue, + Map qosProperties) { + System.out.println("Reached: monitorValueNotifyReceived() -> " + timestamp + " " + samplingTime + " " + newValue); + // all subscription keys are used in all the tests + NullableAttributeList keyValues = updateHeader.getKeyValues(); + Identifier parameterKey = null; + UInteger parameterVersion = null; + if (keyValues == null || keyValues.size() != 2) { + addTestException("Unexpected number of subscription key values"); + } else { + Attribute pKey = keyValues.get(0).getValue(); + if (pKey != null) + parameterKey = (Identifier) pKey; + Attribute pVersion = keyValues.get(1).getValue(); + if (pVersion != null) + parameterVersion = (UInteger) pVersion; + } + synchronized(this) { + valueUpdates.add(new MonitorValueUpdate( + updateHeader.getDomain(), + parameterKey, parameterVersion, + timestamp, samplingTime, newValue)); + notify(); + } + } + @Override + public void monitorValueNotifyErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: monitorValueNotifyErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + @Override + public void monitorValueDeregisterAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: monitorValueDeregisterAckReceived()"); + synchronized(this) { + deregisterAckReceived = true; + notify(); + } + } + + @Override + public void getReportingConfigurationResponseReceived( + MALMessageHeader msgHeader, + ReportConfigurationList reportConfigs, + Map qosProperties) { + System.out.println("Reached: getReportingConfigurationResponseReceived()"); + if (reportConfigs == null) { + // OUT field is not nullable + addTestException("getReportingConfiguration OUT parameter is null"); + } + synchronized(this) { + this.getReportConfigResponse = reportConfigs; + notify(); + } + } + @Override + public void getReportingConfigurationErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: getReportingConfigurationErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void enableReportingAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: enableReportingAckReceived()"); + synchronized(this) { + enableReportingAckReceived = true; + notify(); + } + } + @Override + public void enableReportingErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: enableReportingErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void disableReportingAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: disableReportingAckReceived()"); + synchronized(this) { + disableReportingAckReceived = true; + notify(); + } + } + @Override + public void disableReportingErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: disableReportingErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } + + @Override + public void setReportingPeriodAckReceived( + MALMessageHeader msgHeader, + Map qosProperties) { + System.out.println("Reached: setReportingPeriodAckReceived()"); + synchronized(this) { + setReportingPeriodAckReceived = true; + notify(); + } + } + @Override + public void setReportingPeriodErrorReceived( + MALMessageHeader msgHeader, + MOErrorException error, + Map qosProperties) { + System.out.println("Reached: setReportingPeriodErrorReceived()"); + synchronized(this) { + this.error = error; + notify(); + } + } +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ParameterTestClient.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ParameterTestClient.java new file mode 100755 index 000000000..7360b45bc --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/ParameterTestClient.java @@ -0,0 +1,904 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 European Space Agency + * European Space Operations Centre + * Darmstadt + * Germany + * ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * Adapted to the M&C testbed from the MPD testbed + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import org.ccsds.mo.mc.testbed.ParameterListener.MonitorValueUpdate; +import org.ccsds.moims.mo.mal.MALException; +import org.ccsds.moims.mo.mal.MALInteractionException; +import org.ccsds.moims.mo.mal.structures.Duration; +import org.ccsds.moims.mo.mal.structures.IdentifierList; +import org.ccsds.moims.mo.mal.structures.NullableAttributeList; +import org.ccsds.moims.mo.mal.structures.ObjectRef; +import org.ccsds.moims.mo.mal.structures.Subscription; +import org.ccsds.moims.mo.mal.structures.UInteger; +import org.ccsds.moims.mo.mal.structures.UIntegerList; +import org.ccsds.moims.mo.mc.structures.ParameterDefinition; +import org.ccsds.moims.mo.mc.structures.ParameterValue; +import org.ccsds.moims.mo.mc.structures.ParameterValueData; +import org.ccsds.moims.mo.mc.structures.ParameterValueDataList; +import org.ccsds.moims.mo.mc.structures.ParameterValueList; +import org.ccsds.moims.mo.mc.structures.ReportConfiguration; +import org.ccsds.moims.mo.mc.structures.ReportConfigurationList; + +/** +* This class provides shared functions for all Parameter test clients. +*/ +public class ParameterTestClient extends MCTest { + + public static final Duration DURATION_0 = new Duration(0); + public static final Duration DURATION_60 = new Duration(60); + public static final Duration DURATION_300 = new Duration(300); + public static final Duration DURATION_600 = new Duration(600); + + protected static void execAndCheckMonitorValueRegister( + Subscription subscription, + ParameterListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncMonitorValueRegister( + subscription, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.registerAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate it + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.registerAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckMonitorValueDeregister( + IdentifierList subscriptions, + ParameterListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncMonitorValueDeregister( + subscriptions, + listener); + + // ------------------------------------------------------------------------ + // Wait while ACK has not been received and TIMOUT has not passed yet... + synchronized(listener) { + while (!listener.hasError() && + !listener.deregisterAckReceived && + timeout > 0) { + try { + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate it + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.deregisterAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + /** + * Waits for expected updates and checks them. + * All updates relates to the same Parameter. + * + * @param listener callback listener + * @param maxTime max waiting time + * @param updates expected updates + */ + protected static void waitAndCheckForUpdates( + ParameterListener listener, + long maxTime, + MonitorValueUpdate[] updates) { + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + int nbUpdates = updates.length; + synchronized(listener) { + while (!listener.hasError() && + listener.valueUpdates.size() != nbUpdates && + timeout > 0) { + try { + System.out.println("wait for Updates from subscription"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + System.out.println("end wait, listener=" + listener); + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.valueUpdates.size() != nbUpdates) + unitTestFail("Incorrect number of updates received: " + + "expected " + nbUpdates + + " was " + listener.valueUpdates.size()); + // check received updates + Iterator it = listener.valueUpdates.iterator(); + for (int idx = 0; it.hasNext(); idx++) { + assertEquals("Update[" + idx + "]", updates[idx], it.next()); + } + } + } + + /** + * Waits for expected updates and checks them. + * + * @param listener callback listener + * @param maxTime max waiting time + * @param updatesTab list of expected updates, grouped by Parameter + */ + protected static void waitAndCheckForUpdates( + ParameterListener listener, + long maxTime, + MonitorValueUpdate[][] updatesTab) { + // ------------------------------------------------------------------------ + // Wait for all updates or TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + int nbUpdates = 0; + for (int i=0; i 0) { + try { + System.out.println("wait for Updates from subscription"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + System.out.println("end wait, listener=" + listener); + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.valueUpdates.size() != nbUpdates) + unitTestFail("Incorrect number of updates received: " + + "expected " + nbUpdates + + " was " + listener.valueUpdates.size()); + // check received updates + Hashtable, List> received = + new Hashtable<>(updatesTab.length); + for (int i=0; i( + updatesTab[i][0].domain, + ParameterDefinition.TYPE_ID.getTypeId(), + updatesTab[i][0].parameterKey, + updatesTab[i][0].parameterVersion), + new ArrayList(updatesTab[i].length)); + Iterator it = listener.valueUpdates.iterator(); + while (it.hasNext()) { + MonitorValueUpdate update = it.next(); + List updates = received.get( + new ObjectRef<>( + update.domain, + ParameterDefinition.TYPE_ID.getTypeId(), + update.parameterKey, + update.parameterVersion)); + updates.add(update); + } + for (int i=0; i parameter = new ObjectRef<>( + updatesTab[i][0].domain, + ParameterDefinition.TYPE_ID.getTypeId(), + updatesTab[i][0].parameterKey, + updatesTab[i][0].parameterVersion); + List updates = received.get(parameter); + if (updates.size() != updatesTab[i].length) + unitTestFail("Incorrect number of updates received for Parameter " + parameter + ": " + + "expected " + updatesTab[i].length + + " was " + updates.size()); + it = updates.iterator(); + for (int idx = 0; it.hasNext(); idx++) { + assertEquals( + "Update[" + idx + "] for Parameter " + parameter, + updatesTab[i][idx], it.next()); + } + } + } + } + + protected static void waitAndCheckNoUpdate( + ParameterListener listener, + long maxTime) { + // ------------------------------------------------------------------------ + // Wait for TIMOUT + long timeout = maxTime - System.currentTimeMillis(); + synchronized(listener) { + while (!listener.hasError() && + timeout > 0) { + try { + System.out.println("wait for timeout"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + + // check no new message from subscription + if (!listener.valueUpdates.isEmpty()) + unitTestFail("received unexpected updates"); + } + } + + protected static void execAndCheckGetValue( + IdentifierList domain, + IdentifierList keys, + ParameterListener listener, + long maxTime, + ParameterValueList expected) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncGetValue( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for response or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.getValueResponse == null && + timeout > 0) { + try { + System.out.println("wait for response"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.getValueResponse == null) + unitTestFail("The RESPONSE was not received!"); + + assertEquals("error in getValue RESPONSE", expected, listener.getValueResponse); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorGetValue( + IdentifierList domain, + IdentifierList keys, + ParameterListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncGetValue( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.getValueResponse == null && + timeout > 0) { + try { + System.out.println("wait for response"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.getValueResponse != null) + unitTestFail("Unexpected RESPONSE received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckSetValue( + IdentifierList domain, + IdentifierList keys, + NullableAttributeList newRawValues, + ParameterListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncSetValue( + domain, + keys, + newRawValues, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.setValueAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.setValueAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorSetValue( + IdentifierList domain, + IdentifierList keys, + NullableAttributeList newRawValues, + ParameterListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncSetValue( + domain, + keys, + newRawValues, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.setValueAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.setValueAckReceived) + unitTestFail("Unexpected RESPONSE received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckGetReportingConfiguration( + IdentifierList domain, + IdentifierList keys, + ParameterListener listener, + long maxTime, + ReportConfigurationList expected) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncGetReportingConfiguration( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for response or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + listener.getReportConfigResponse == null && + timeout > 0) { + try { + System.out.println("wait for response"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (listener.getReportConfigResponse == null) + unitTestFail("The RESPONSE was not received!"); + + assertEquals("error in getReportingConfiguration RESPONSE", expected, listener.getReportConfigResponse); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckEnableReporting( + IdentifierList domain, + IdentifierList keys, + ParameterListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncEnableReporting( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.enableReportingAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.enableReportingAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorEnableReporting( + IdentifierList domain, + IdentifierList keys, + ParameterListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncEnableReporting( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.enableReportingAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.enableReportingAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckDisableReporting( + IdentifierList domain, + IdentifierList keys, + ParameterListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncDisableReporting( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.disableReportingAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.disableReportingAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorDisableReporting( + IdentifierList domain, + IdentifierList keys, + ParameterListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncDisableReporting( + domain, + keys, + listener); + + // ------------------------------------------------------------------------ + // Wait for ERROR or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.disableReportingAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.disableReportingAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + protected static void execAndCheckSetReportingPeriod( + IdentifierList domain, + IdentifierList keys, + Duration reportInterval, + ParameterListener listener, + long maxTime) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncSetReportingPeriod( + domain, + keys, + reportInterval, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.setReportingPeriodAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.hasError()) + unitTestFail(listener.getError()); + if (!listener.setReportingPeriodAckReceived) + unitTestFail("The ACK was not received!"); + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + protected static void execAndCheckErrorSetReportingPeriod( + IdentifierList domain, + IdentifierList keys, + Duration reportInterval, + ParameterListener listener, + long maxTime, + UInteger errorNumber, + Object extraInfo) { + + try { + long timeout = maxTime - System.currentTimeMillis(); + parameterConsumerStub.asyncSetReportingPeriod( + domain, + keys, + reportInterval, + listener); + + // ------------------------------------------------------------------------ + // Wait for ack or TIMOUT + synchronized(listener) { + while (!listener.hasError() && + !listener.setReportingPeriodAckReceived && + timeout > 0) { + try { + System.out.println("wait for ACK"); + listener.wait(timeout); + } catch (InterruptedException e) {} + // Recalculate timer + timeout = maxTime - System.currentTimeMillis(); + } + if (listener.setReportingPeriodAckReceived) + unitTestFail("Unexpected ACK received"); + if (listener.error == null) + unitTestFail("Missing expected ACK error"); + if (!errorNumber.equals(listener.error.getErrorNumber())) + unitTestFail("Wrong error received" + + ", expecting " + errorNumber + + ", was " + listener.error); + if (extraInfo != null) { + if (extraInfo instanceof UIntegerList) { + assertEquals( + "Error in extraInfo field", + (UIntegerList) extraInfo, + (UIntegerList) listener.error.getExtraInformation()); + } else if (!extraInfo.equals(listener.error.getExtraInformation())) { + unitTestFail("Error in extraInfo field" + + ", expecting " + extraInfo + + ", was " + listener.error.getExtraInformation()); + } + } + } + } catch (MALInteractionException exc) { + unitTestFail(exc); + } catch (MALException exc) { + unitTestFail(exc); + } + } + + public static void assertEquals(String error, ParameterValueList expected, ParameterValueList actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); + } + } + public static void assertEquals(String error, ParameterValue expected, ParameterValue actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected value, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); + assertEquals(error + " paramRef", expected.getParamRef(), actual.getParamRef()); + // ignore timestamp and samplingTime + assertEquals(error + " value", expected.getValue(), actual.getValue()); + } + public static void assertEquals(String error, ParameterValueDataList expected, ParameterValueDataList actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected list, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); + } + } + public static void assertEquals(String error, ParameterValueData expected, ParameterValueData actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected value, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); + if (!expected.getValidityState().equals(actual.getValidityState())) + unitTestFail(error + " unexpected validity state, expecting " + expected.getValidityState() + ", was " + actual.getValidityState()); + if (expected.getRawValue() == null && actual.getRawValue() != null || + expected.getRawValue() != null && !expected.getRawValue().equals(actual.getRawValue())) + unitTestFail(error + " unexpected raw value, expecting " + expected.getRawValue() + ", was " + actual.getRawValue()); + if (expected.getConvertedValue() == null && actual.getConvertedValue() != null || + expected.getConvertedValue() != null && !expected.getConvertedValue().equals(actual.getConvertedValue())) + unitTestFail(error + " unexpected converted value, expecting " + expected.getConvertedValue() + ", was " + actual.getConvertedValue()); + } + + public static void assertEquals(String error, ReportConfigurationList expected, ReportConfigurationList actual) { + if (expected == null) { + if (actual != null) + unitTestFail(error + " unexpected list, expecting null, was " + actual); + return; + } + if (actual == null) + unitTestFail(error + " unexpected list, expecting " + expected + ", was " + actual); + if (actual.size() != expected.size()) + unitTestFail(error + " wrong list size, expecting " + expected.size() + ", was " + actual.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(error + " [" + i + "]", expected.get(i), actual.get(i)); + } + } + public static void assertEquals(String error, ReportConfiguration expected, ReportConfiguration actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + " unexpected value, expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + " unexpected value, expecting " + expected + ", was " + actual); + if (expected.getGenerationEnabled() == null && actual.getGenerationEnabled() != null || + expected.getGenerationEnabled() != null && !expected.getGenerationEnabled().equals(actual.getGenerationEnabled())) + unitTestFail(error + " unexpected generationEnabled, expecting " + expected.getGenerationEnabled() + ", was " + actual.getGenerationEnabled()); + if (expected.getReportInterval() == null && actual.getReportInterval() != null || + expected.getReportInterval() != null && !expected.getReportInterval().equals(actual.getReportInterval())) + unitTestFail(error + " unexpected reportInterval, expecting " + expected.getReportInterval() + ", was " + actual.getReportInterval()); + } + + public static void assertEquals( + String error, + MonitorValueUpdate expected, + MonitorValueUpdate actual) { + if (expected == null) { + if (actual == null) + return; + unitTestFail(error + ", expecting null, was " + actual); + } + if (actual == null) + unitTestFail(error + ", expecting " + expected + ", was " + actual); + if (!expected.domain.equals(actual.domain)) + unitTestFail(error + " unexpected domain" + + ", expecting " + expected.domain + + ", was " + actual.domain); + if (!actual.parameterKey.equals(expected.parameterKey)) + unitTestFail(error + " unexpected parameterKey subscription key" + + ", expecting " + expected.parameterKey + + ", was " + actual.parameterKey); + if (!actual.parameterVersion.equals(expected.parameterVersion)) + unitTestFail(error + " unexpected parameterVersion subscription key" + + ", expecting " + expected.parameterVersion + + ", was " + actual.parameterVersion); + assertEquals(error + " value data", expected.newValue, actual.newValue); + } +} \ No newline at end of file diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/TestDependency.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/TestDependency.java new file mode 100755 index 000000000..df9721e10 --- /dev/null +++ b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/TestDependency.java @@ -0,0 +1,73 @@ +/* ---------------------------------------------------------------------------- + * Copyright (C) 2025 CNES, France + * Copyright (C) 2025 Serge Lacourte + * ---------------------------------------------------------------------------- + * System : CCSDS MO Testbed - M&C + * ---------------------------------------------------------------------------- + * Licensed under the European Space Agency Public License, Version 2.0 + * You may not use this file except in compliance with the License. + * + * Except as expressly set forth in this License, the Software is provided to + * You on an "as is" basis and without warranties of any kind, including without + * limitation merchantability, fitness for a particular purpose, absence of + * defects or errors, accuracy or non-infringement of intellectual property rights. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + */ +package org.ccsds.mo.mc.testbed; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Method; + +/** + * This class is used to help managing dependencies between tests. + * The M&C testbed does not always follow the standard pattern of JUnit tests + * where tests should be completely independant. + * Dependant tests use the before and after functions to be called at the beginning and at the end of the test. + * + * @author serge + * + */ +public class TestDependency { + + private static int testStep = 0; + private static boolean testStatus = true; + public interface TestProcedure { + void exec(); + } + + public static void reset() { + testStep = 0; + testStatus = true; + } + + /** + * Checks that the dependant test has executed and successfully completed. + */ + public static void before(int previousStep, Object testObject, String previousTestProcName, int targetStep) { + assertTrue("Previous dependant test failed.", testStatus); + if (previousTestProcName != null && testStep != previousStep) { + try { + assertNotNull(testObject); + Method previousTestProc = testObject.getClass().getMethod(previousTestProcName, (Class[] ) null); + previousTestProc.invoke(testObject, (Object[]) null); + } catch (ReflectiveOperationException exc) { + assertNull(exc.getMessage(), exc); + } + } + testStep = targetStep; + testStatus = false; + } + + /** + * Validates the current test step for the depending test. + */ + public static void after() { + testStatus = true; + } +} diff --git a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/UC1_Ex1_Test.java b/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/UC1_Ex1_Test.java deleted file mode 100644 index 0c43d3f6c..000000000 --- a/testbeds/testbed-mc/src/test/java/org/ccsds/mo/mc/testbed/UC1_Ex1_Test.java +++ /dev/null @@ -1,66 +0,0 @@ -/* ---------------------------------------------------------------------------- - * Copyright (C) 2025 European Space Agency - * European Space Operations Centre - * Darmstadt - * Germany - * ---------------------------------------------------------------------------- - * System : CCSDS MO Testbed - * ---------------------------------------------------------------------------- - * Licensed under the European Space Agency Public License, Version 2.0 - * You may not use this file except in compliance with the License. - * - * Except as expressly set forth in this License, the Software is provided to - * You on an "as is" basis and without warranties of any kind, including without - * limitation merchantability, fitness for a particular purpose, absence of - * defects or errors, accuracy or non-infringement of intellectual property rights. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * ---------------------------------------------------------------------------- - */ -package org.ccsds.mo.mc.testbed; - -import java.io.IOException; -import org.ccsds.moims.mo.mal.structures.UInteger; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * - */ -public class UC1_Ex1_Test extends MCTest { - - @BeforeClass - public static void setUpClass() throws IOException { - System.out.println(TEST_SET_UP_CLASS_1); - System.out.println(TEST_SET_UP_CLASS_2); - //setUp.setUp(backend, true, true, true); - } - - /** - * Test Case 1. - */ - @Test - public void testCase_01() { - System.out.println("Running: testCase_1()"); - UInteger apidValue = new UInteger(100); - test(apidValue, 1); - } - - /** - * Test Case 2. - */ - @Test - public void testCase_02() { - System.out.println("Running: testCase_2()"); - UInteger apidValue = new UInteger(200); - test(apidValue, 1); - } - - private void test(UInteger apidValue, int expectedNumberOfResults) { - testWithTimeWindow(apidValue, expectedNumberOfResults); - } - - private synchronized void testWithTimeWindow(UInteger apidValue, int expectedNumberOfResults) { - } -} diff --git a/testbeds/xml-tests/src/main/resources/MCPrototype.xml b/testbeds/xml-tests/src/main/resources/MCPrototype.xml index 77b464e76..eafce420b 100644 --- a/testbeds/xml-tests/src/main/resources/MCPrototype.xml +++ b/testbeds/xml-tests/src/main/resources/MCPrototype.xml @@ -1,11 +1,10 @@ + xmlns:mal="http://www.ccsds.org/schema/ServiceSchema-v003"> + version="2"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +