diff --git a/CHANGELOG.md b/CHANGELOG.md
index bd93537c..69cf9cd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- report duplication issue in biceps:C11-C15, biceps:C5, biceps:R5046_0, biceps:B-284_0 as well as biceps:R5003.
- biceps:5-4-7 tests confusing changes made by SetComponentActivation manipulations with changes made by SetMetricStatus.
- glue:R0036_0 test can be blocked by long-running t2iapi RPCs.
+- biceps:5025_0 test case could not be satisfied by devices that do not support inserting and removing descriptors.
## [7.0.1] - 2023-03-17
diff --git a/README.md b/README.md
index 1243c9eb..65f0e978 100644
--- a/README.md
+++ b/README.md
@@ -288,7 +288,7 @@ this case in order to minimize the risk of such an invalid application going unn
| C-14 | TriggerReport |
| C-15 | TriggerReport |
| R5024 | TriggerReport |
-| R5025_0 | GetRemovableDescriptorsOfClass, RemoveDescriptor, InsertDescriptor |
+| R5025_0 | GetRemovableDescriptorsOfClass, RemoveDescriptor, InsertDescriptor, TriggerDescriptorUpdate |
| R5046_0 | GetRemovableDescriptorsOfClass, RemoveDescriptor, InsertDescriptor |
| R5051 | GetRemovableDescriptorsOfClass, RemoveDescriptor, InsertDescriptor |
| R5052 | TriggerAnyDescriptorUpdate |
diff --git a/sdccc/pom.xml b/sdccc/pom.xml
index 83c1782d..e5d185a0 100644
--- a/sdccc/pom.xml
+++ b/sdccc/pom.xml
@@ -172,7 +172,7 @@
com.draeger.medical
t2iapi
- 3.0.0.262
+ 3.0.0.296
diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/FallbackManipulations.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/FallbackManipulations.java
index b2d178ba..64d8af26 100644
--- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/FallbackManipulations.java
+++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/FallbackManipulations.java
@@ -234,6 +234,19 @@ public void close() {}
return interactionResult ? ResponseTypes.Result.RESULT_SUCCESS : ResponseTypes.Result.RESULT_FAIL;
}
+ @Override
+ public ResponseTypes.Result triggerDescriptorUpdate(final List handles) {
+ final var triggerReportString = "Trigger a descriptor update for handles %s";
+ final var interactionMessage = String.format(triggerReportString, String.join(", ", handles));
+ final var interactionResult = interactionFactory
+ .createUserInteraction(new FilterInputStream(System.in) {
+ @Override
+ public void close() {}
+ })
+ .displayYesNoUserInteraction(interactionMessage);
+ return interactionResult ? ResponseTypes.Result.RESULT_SUCCESS : ResponseTypes.Result.RESULT_FAIL;
+ }
+
@Override
public ResponseTypes.Result triggerAnyDescriptorUpdate() {
final var interactionMessage = "Trigger a descriptor update for some descriptor";
diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/GRpcManipulations.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/GRpcManipulations.java
index 57283c20..05ce40e9 100644
--- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/GRpcManipulations.java
+++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/GRpcManipulations.java
@@ -294,15 +294,21 @@ public ResponseTypes.Result setMetricStatus(
@Override
public ResponseTypes.Result triggerDescriptorUpdate(final String handle) {
- final var message =
- BasicRequests.BasicHandleRequest.newBuilder().setHandle(handle).build();
+ return triggerDescriptorUpdate(List.of(handle));
+ }
+
+ @Override
+ public ResponseTypes.Result triggerDescriptorUpdate(final List handles) {
+ final var message = DeviceRequests.TriggerDescriptorUpdateRequest.newBuilder()
+ .addAllHandle(handles)
+ .build();
return performCallWrapper(
v -> deviceStub.triggerDescriptorUpdate(message),
- v -> fallback.triggerDescriptorUpdate(handle),
+ v -> fallback.triggerDescriptorUpdate(handles),
BasicResponses.BasicResponse::getResult,
BasicResponses.BasicResponse::getResult,
- ManipulationParameterUtil.buildHandleManipulationParameterData(handle));
+ ManipulationParameterUtil.buildTriggerDescriptorUpdateParameterData(handles));
}
@Override
diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/Manipulations.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/Manipulations.java
index 64fbd73a..639f7e8d 100644
--- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/Manipulations.java
+++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/Manipulations.java
@@ -137,6 +137,14 @@ ResponseTypes.Result setMetricStatus(
*/
ResponseTypes.Result triggerDescriptorUpdate(String handle);
+ /**
+ * Trigger a descriptor update for the provided descriptor handles.
+ *
+ * @param handles list of descriptor handles to trigger an update for.
+ * @return the result of the manipulation
+ */
+ ResponseTypes.Result triggerDescriptorUpdate(List handles);
+
/**
* Trigger a descriptor update for some descriptor (chosen by the device).
*
diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditions.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditions.java
index e93e8762..2494891c 100644
--- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditions.java
+++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditions.java
@@ -461,11 +461,11 @@ static boolean manipulation(final Injector injector) {
}
// all options exhausted and the goal is still not reached
- LOG.error("Unable to find any MdsDescriptors using the GetRemovableDescriptorsOfType() manipulation "
+ LOG.error("Unable to find any MdsDescriptors using the GetRemovableDescriptorsOfClass() manipulation "
+ "that can be inserted, updated and removed (at least one for each is required for the test "
+ "applying this precondition). "
+ "Please check if the test case applying this precondition is applicable to your device and if the "
- + "GetRemovableDescriptorsOfType, InsertDescriptor, RemoveDescriptor, and TriggerDescriptorUpdate "
+ + "GetRemovableDescriptorsOfClass, InsertDescriptor, RemoveDescriptor, and TriggerDescriptorUpdate "
+ "manipulations have been implemented correctly.");
return false;
}
@@ -660,15 +660,17 @@ static boolean manipulation(final Injector injector) {
* Precondition which checks whether DescriptionModificationReport messages containing an insertion
* or deletion have been received, triggering description changes otherwise.
*/
- public static class DescriptionChangedPrecondition extends SimplePrecondition {
+ public static class DescriptionModificationCrtOrDelPrecondition extends SimplePrecondition {
- private static final Logger LOG = LogManager.getLogger(DescriptionChangedPrecondition.class);
+ private static final Logger LOG = LogManager.getLogger(DescriptionModificationCrtOrDelPrecondition.class);
/**
- * Creates a description changed precondition check.
+ * Creates a description modification crt or del precondition check.
*/
- public DescriptionChangedPrecondition() {
- super(DescriptionChangedPrecondition::preconditionCheck, DescriptionChangedPrecondition::manipulation);
+ public DescriptionModificationCrtOrDelPrecondition() {
+ super(
+ DescriptionModificationCrtOrDelPrecondition::preconditionCheck,
+ DescriptionModificationCrtOrDelPrecondition::manipulation);
}
static boolean preconditionCheck(final Injector injector) throws PreconditionException {
diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditions.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditions.java
index db31af2e..f3199a0e 100644
--- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditions.java
+++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditions.java
@@ -10,6 +10,7 @@
import com.draeger.medical.sdccc.configuration.TestSuiteConfig;
import com.draeger.medical.sdccc.manipulation.Manipulations;
import com.draeger.medical.sdccc.manipulation.precondition.ManipulationPrecondition;
+import com.draeger.medical.sdccc.manipulation.precondition.PreconditionException;
import com.draeger.medical.sdccc.sdcri.testclient.TestClient;
import com.draeger.medical.sdccc.tests.util.ImpliedValueUtil;
import com.draeger.medical.sdccc.util.TestRunObserver;
@@ -29,6 +30,7 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.somda.sdc.biceps.common.MdibEntity;
@@ -38,6 +40,7 @@
import org.somda.sdc.biceps.common.event.ContextStateModificationMessage;
import org.somda.sdc.biceps.model.participant.AbstractAlertState;
import org.somda.sdc.biceps.model.participant.AbstractContextState;
+import org.somda.sdc.biceps.model.participant.AbstractDescriptor;
import org.somda.sdc.biceps.model.participant.AbstractDeviceComponentDescriptor;
import org.somda.sdc.biceps.model.participant.AbstractDeviceComponentState;
import org.somda.sdc.biceps.model.participant.AbstractMetricDescriptor;
@@ -55,6 +58,7 @@
import org.somda.sdc.biceps.model.participant.ContextAssociation;
import org.somda.sdc.biceps.model.participant.LocationContextDescriptor;
import org.somda.sdc.biceps.model.participant.LocationContextState;
+import org.somda.sdc.biceps.model.participant.MdsDescriptor;
import org.somda.sdc.biceps.model.participant.MetricCategory;
import org.somda.sdc.biceps.model.participant.PatientContextDescriptor;
import org.somda.sdc.biceps.model.participant.PatientContextState;
@@ -114,6 +118,114 @@ private static boolean manipulateMetricStatus(
return manipulationResults.contains(ResponseTypes.Result.RESULT_SUCCESS);
}
+ private static boolean removeAndReinsertDescriptors(final Injector injector, final Logger log) {
+ final var manipulations = injector.getInstance(Manipulations.class);
+ final var testClient = injector.getInstance(TestClient.class);
+ final var testRunObserver = injector.getInstance(TestRunObserver.class);
+
+ final MdibAccess mdibAccess;
+ final SdcRemoteDevice remoteDevice;
+
+ remoteDevice = testClient.getSdcRemoteDevice();
+ if (remoteDevice == null) {
+ testRunObserver.invalidateTestRun("Remote device could not be accessed, likely due to a disconnect");
+ return false;
+ }
+
+ mdibAccess = remoteDevice.getMdibAccess();
+
+ final var modifiableDescriptors = manipulations.getRemovableDescriptorsOfClass();
+ if (modifiableDescriptors.isEmpty()) {
+ log.info("No modifiable descriptors available for manipulation");
+ return false;
+ }
+
+ final var manipulationResults = new HashSet();
+ for (String handle : modifiableDescriptors) {
+ // determine if descriptor is currently present
+ var descriptorEntity = mdibAccess.getEntity(handle);
+ log.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent());
+
+ // if the descriptor is not present, insert it first
+ if (descriptorEntity.isEmpty()) {
+ manipulationResults.add(manipulations.insertDescriptor(handle));
+ descriptorEntity = mdibAccess.getEntity(handle);
+ if (descriptorEntity.isEmpty()) {
+ manipulationResults.add(ResponseTypes.Result.RESULT_FAIL);
+ }
+ log.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent());
+ }
+
+ // remove descriptor
+ manipulationResults.add(manipulations.removeDescriptor(handle));
+ descriptorEntity = mdibAccess.getEntity(handle);
+ if (descriptorEntity.isPresent()) {
+ manipulationResults.add(ResponseTypes.Result.RESULT_FAIL);
+ }
+ log.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent());
+
+ // reinsert descriptor
+ manipulationResults.add(manipulations.insertDescriptor(handle));
+ descriptorEntity = mdibAccess.getEntity(handle);
+ if (descriptorEntity.isEmpty()) {
+ manipulationResults.add(ResponseTypes.Result.RESULT_FAIL);
+ }
+ log.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent());
+
+ if (manipulationResults.contains(ResponseTypes.Result.RESULT_FAIL)) {
+ testRunObserver.invalidateTestRun(String.format(
+ "Could not successfully modify descriptor %s, stopping the precondition", handle));
+ break;
+ }
+ }
+
+ return !manipulationResults.contains(ResponseTypes.Result.RESULT_FAIL)
+ && !manipulationResults.contains(ResponseTypes.Result.RESULT_NOT_IMPLEMENTED)
+ && manipulationResults.contains(ResponseTypes.Result.RESULT_SUCCESS);
+ }
+
+ private static boolean descriptionUpdateWithParentChildRelationshipManipulation(
+ final Injector injector, final Logger log) {
+ final Pair descriptorHandles = findFirstDescriptorHandleWithChildren(injector, log);
+ if (descriptorHandles == null) {
+ log.error("Could not trigger a descriptor update with parent child relationship as there are no "
+ + "descriptors with children in the mdib.");
+ return false;
+ }
+ final String parentDescriptorHandle = descriptorHandles.getLeft();
+ final String childDescriptorHandle = descriptorHandles.getRight();
+ final var manipulations = injector.getInstance(Manipulations.class);
+
+ final ResponseTypes.Result manipulationResult =
+ manipulations.triggerDescriptorUpdate(List.of(childDescriptorHandle, parentDescriptorHandle));
+
+ return ResponseTypes.Result.RESULT_SUCCESS.equals(manipulationResult);
+ }
+
+ private static Pair findFirstDescriptorHandleWithChildren(
+ final Injector injector, final Logger log) {
+ final var testClient = injector.getInstance(TestClient.class);
+
+ final var remoteDevice = testClient.getSdcRemoteDevice();
+ if (remoteDevice == null) {
+ log.error("remote device could not be accessed, likely due to a disconnect");
+ return null;
+ }
+ final var mdibAccess = remoteDevice.getMdibAccess();
+
+ final Collection entities = mdibAccess.findEntitiesByType(AbstractDescriptor.class);
+ for (MdibEntity entity : entities) {
+ if (entity.getDescriptor() instanceof MdsDescriptor) {
+ continue; // we are not interested in MdsDescriptors as many Devices do not support modifying them.
+ }
+ final List children = entity.getChildren();
+ if (!children.isEmpty()) {
+ return Pair.of(entity.getHandle(), children.get(0));
+ }
+ }
+ return null;
+ }
+
/**
* Associates two new patients for every available PatientContextDescriptor present in the provider mdib.
*/
@@ -1607,69 +1719,37 @@ public RemoveAndReinsertDescriptorManipulation() {
* @return true if successful, false otherwise
*/
static boolean manipulation(final Injector injector) {
- final var manipulations = injector.getInstance(Manipulations.class);
- final var testClient = injector.getInstance(TestClient.class);
- final var testRunObserver = injector.getInstance(TestRunObserver.class);
-
- final MdibAccess mdibAccess;
- final SdcRemoteDevice remoteDevice;
-
- remoteDevice = testClient.getSdcRemoteDevice();
- if (remoteDevice == null) {
- testRunObserver.invalidateTestRun("Remote device could not be accessed, likely due to a disconnect");
- return false;
- }
-
- mdibAccess = remoteDevice.getMdibAccess();
-
- final var modifiableDescriptors = manipulations.getRemovableDescriptorsOfClass();
- if (modifiableDescriptors.isEmpty()) {
- LOG.info("No modifiable descriptors available for manipulation");
- return false;
- }
-
- final var manipulationResults = new HashSet();
- for (String handle : modifiableDescriptors) {
- // determine if descriptor is currently present
- var descriptorEntity = mdibAccess.getEntity(handle);
- LOG.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent());
-
- // if the descriptor is not present, insert it first
- if (descriptorEntity.isEmpty()) {
- manipulationResults.add(manipulations.insertDescriptor(handle));
- descriptorEntity = mdibAccess.getEntity(handle);
- if (descriptorEntity.isEmpty()) {
- manipulationResults.add(ResponseTypes.Result.RESULT_FAIL);
- }
- LOG.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent());
- }
+ return removeAndReinsertDescriptors(injector, LOG);
+ }
+ }
- // remove descriptor
- manipulationResults.add(manipulations.removeDescriptor(handle));
- descriptorEntity = mdibAccess.getEntity(handle);
- if (descriptorEntity.isPresent()) {
- manipulationResults.add(ResponseTypes.Result.RESULT_FAIL);
- }
- LOG.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent());
+ /**
+ * Precondition which triggers all possible description changes with parent-child relationships.
+ */
+ public static class DescriptionModificationAllWithParentChildRelationshipPrecondition
+ extends ManipulationPrecondition {
- // reinsert descriptor
- manipulationResults.add(manipulations.insertDescriptor(handle));
- descriptorEntity = mdibAccess.getEntity(handle);
- if (descriptorEntity.isEmpty()) {
- manipulationResults.add(ResponseTypes.Result.RESULT_FAIL);
- }
- LOG.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent());
+ private static final Logger LOG =
+ LogManager.getLogger(DescriptionModificationAllWithParentChildRelationshipPrecondition.class);
- if (manipulationResults.contains(ResponseTypes.Result.RESULT_FAIL)) {
- testRunObserver.invalidateTestRun(String.format(
- "Could not successfully modify descriptor %s, stopping the precondition", handle));
- break;
- }
- }
+ /**
+ * Creates a description modification all with parent child relationship precondition check.
+ */
+ public DescriptionModificationAllWithParentChildRelationshipPrecondition() {
+ super(DescriptionModificationAllWithParentChildRelationshipPrecondition::manipulation);
+ }
- return !manipulationResults.contains(ResponseTypes.Result.RESULT_FAIL)
- && !manipulationResults.contains(ResponseTypes.Result.RESULT_NOT_IMPLEMENTED)
- && manipulationResults.contains(ResponseTypes.Result.RESULT_SUCCESS);
+ /**
+ * Performs the removal, reinsertion and update of all modifiable descriptors in the mdib to trigger reports.
+ *
+ * @param injector to analyze mdib on
+ * @return true if successful, false otherwise
+ * @throws PreconditionException on errors
+ */
+ static boolean manipulation(final Injector injector) {
+ final boolean result1 = removeAndReinsertDescriptors(injector, LOG);
+ final boolean result2 = descriptionUpdateWithParentChildRelationshipManipulation(injector, LOG);
+ return result1 || result2;
}
}
}
diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantMessageModelAnnexTest.java b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantMessageModelAnnexTest.java
index 6416d3b1..f0a1edb2 100644
--- a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantMessageModelAnnexTest.java
+++ b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantMessageModelAnnexTest.java
@@ -15,6 +15,7 @@
import com.draeger.medical.sdccc.configuration.EnabledTestConfig;
import com.draeger.medical.sdccc.manipulation.precondition.impl.ConditionalPreconditions;
+import com.draeger.medical.sdccc.manipulation.precondition.impl.ManipulationPreconditions;
import com.draeger.medical.sdccc.messages.MessageStorage;
import com.draeger.medical.sdccc.messages.mapping.MessageContent;
import com.draeger.medical.sdccc.sdcri.testclient.TestClient;
@@ -332,7 +333,9 @@ void testRequirementR5024() throws NoTestData, IOException {
@TestDescription("For every DescriptionModificationReport received from the DUT, and for all parent-child"
+ " relationships between the elements contained in the report, checks that the reportPart containing"
+ " the parent comes before the reportPart containing the child.")
- @RequirePrecondition(simplePreconditions = ConditionalPreconditions.DescriptionChangedPrecondition.class)
+ @RequirePrecondition(
+ manipulationPreconditions =
+ ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition.class)
void testRequirementR5025() throws NoTestData, IOException {
try (final var messages =
messageStorage.getInboundMessagesByBodyType(Constants.MSG_DESCRIPTION_MODIFICATION_REPORT)) {
@@ -353,7 +356,10 @@ void testRequirementR5025() throws NoTestData, IOException {
assertTestData(
descriptorsSeen.get(),
"No DescriptionModificationReports with Parent-Child Relationships between Descriptors "
- + " seen during test run, test failed.");
+ + " seen during test run, test failed."
+ + " Please make sure that the device either supports descriptor updates or that the list"
+ + " of removable descriptors returned by the getRemovableDescriptors() manipulation"
+ + " includes at least one descriptor that has child descriptors.");
}
}
diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantParticipantModelVersioningTest.java b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantParticipantModelVersioningTest.java
index a07d948b..0e8d37c5 100644
--- a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantParticipantModelVersioningTest.java
+++ b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantParticipantModelVersioningTest.java
@@ -80,7 +80,8 @@ void setUp() {
@TestDescription(
"Starting from the initially retrieved mdib, applies every episodic report to the mdib and"
+ " verifies that descriptor versions are incremented by 1 whenever a child descriptor is added or deleted.")
- @RequirePrecondition(simplePreconditions = {ConditionalPreconditions.DescriptionChangedPrecondition.class})
+ @RequirePrecondition(
+ simplePreconditions = {ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.class})
void testRequirementR0033() throws NoTestData, IOException {
final var mdibHistorian = mdibHistorianFactory.createMdibHistorian(
messageStorage, getInjector().getInstance(TestRunObserver.class));
diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/util/ManipulationParameterUtil.java b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/util/ManipulationParameterUtil.java
index 1f653ba4..1fd762a8 100644
--- a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/util/ManipulationParameterUtil.java
+++ b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/util/ManipulationParameterUtil.java
@@ -48,6 +48,17 @@ public static ManipulationParameterData buildHandleManipulationParameterData(fin
List.of(new ImmutablePair<>(Constants.MANIPULATION_PARAMETER_HANDLE, handle)));
}
+ /**
+ * Build manipulation parameter data containing the handles that are needed for the manipulation.
+ *
+ * @param handles for which manipulation parameter data will be built.
+ * @return the manipulation parameter data
+ */
+ public static ManipulationParameterData buildTriggerDescriptorUpdateParameterData(final List handles) {
+ return new ManipulationParameterData(
+ List.of(new ImmutablePair<>(Constants.MANIPULATION_PARAMETER_HANDLES, String.join(", ", handles))));
+ }
+
/**
* Build manipulation parameter data containing the location detail that is needed for the manipulation.
*
diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/util/Constants.java b/sdccc/src/main/java/com/draeger/medical/sdccc/util/Constants.java
index c9308c7c..a29b84ac 100644
--- a/sdccc/src/main/java/com/draeger/medical/sdccc/util/Constants.java
+++ b/sdccc/src/main/java/com/draeger/medical/sdccc/util/Constants.java
@@ -222,6 +222,7 @@ public final class Constants {
// Manipulation Data for Hibernation
public static final String MANIPULATION_PARAMETER_HANDLE = "Handle";
+ public static final String MANIPULATION_PARAMETER_HANDLES = "Handles";
public static final String MANIPULATION_PARAMETER_SEQUENCE_ID = "SequenceId";
public static final String MANIPULATION_PARAMETER_LOCATION_DETAIL = "LocationDetail";
public static final String MANIPULATION_PARAMETER_CONTEXT_ASSOCIATION = "ContextAssociation";
diff --git a/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditionsTest.java b/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditionsTest.java
index 23662726..6cbab165 100644
--- a/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditionsTest.java
+++ b/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditionsTest.java
@@ -282,10 +282,11 @@ protected void configure() {
*/
@Test
@DisplayName("DescriptionChangedPrecondition correctly checks for precondition")
- public void testDescriptionModificationPreconditionCheck()
+ public void testDescriptionModificationCrtOrDelPreconditionCheck()
throws PreconditionException, IOException, JAXBException {
// no messages
- assertFalse(ConditionalPreconditions.DescriptionChangedPrecondition.preconditionCheck(testInjector));
+ assertFalse(
+ ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.preconditionCheck(testInjector));
final var reportPart = messageBuilder.buildDescriptionModificationReportReportPart();
reportPart.setModificationType(DescriptionModificationType.CRT);
@@ -297,7 +298,8 @@ public void testDescriptionModificationPreconditionCheck()
messageStorageUtil.addInboundSecureHttpMessage(storage, message);
- assertTrue(ConditionalPreconditions.DescriptionChangedPrecondition.preconditionCheck(testInjector));
+ assertTrue(
+ ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.preconditionCheck(testInjector));
}
/**
@@ -334,7 +336,7 @@ public void testDescriptionModificationManipulation() {
}
});
- assertTrue(ConditionalPreconditions.DescriptionChangedPrecondition.manipulation(testInjector));
+ assertTrue(ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.manipulation(testInjector));
final var insertCaptor = ArgumentCaptor.forClass(String.class);
final var removeCaptor = ArgumentCaptor.forClass(String.class);
@@ -640,7 +642,7 @@ public void testDescriptionModificationDelManipulation() {
@DisplayName("DescriptionModificationPrecondition throws exception if no removable descriptors are present")
void testDescriptionModificationModificationNoDescriptors() {
// must fail without any removable descriptors
- assertFalse(ConditionalPreconditions.DescriptionChangedPrecondition.manipulation(testInjector));
+ assertFalse(ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.manipulation(testInjector));
reset(mockManipulations);
}
diff --git a/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditionsTest.java b/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditionsTest.java
index 199b5142..1da74afb 100644
--- a/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditionsTest.java
+++ b/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditionsTest.java
@@ -13,6 +13,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -24,6 +25,8 @@
import com.draeger.medical.sdccc.manipulation.Manipulations;
import com.draeger.medical.sdccc.sdcri.testclient.TestClient;
+import com.draeger.medical.sdccc.sdcri.testclient.TestClientUtil;
+import com.draeger.medical.sdccc.tests.InjectorTestBase;
import com.draeger.medical.sdccc.tests.test_util.InjectorUtil;
import com.draeger.medical.sdccc.util.MdibBuilder;
import com.draeger.medical.sdccc.util.TestRunObserver;
@@ -32,6 +35,7 @@
import com.google.inject.Injector;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -47,6 +51,7 @@
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
import org.somda.sdc.biceps.common.MdibEntity;
import org.somda.sdc.biceps.common.access.MdibAccess;
import org.somda.sdc.biceps.common.access.MdibAccessObservable;
@@ -95,7 +100,6 @@ public class ManipulationPreconditionsTest {
private static final String ALERT_SYSTEM_CONTEXT_HANDLE2 = "alerthandle2";
private static final String ALERT_CONDITION_HANDLE = "alertconditionhandle";
private static final String ALERT_CONDITION_HANDLE2 = "alertconditionhandle2";
- private static final String ALERT_SIGNAL_HANDLE = "alertSignalHandle";
private static final String AUD_ALERT_SIGNAL_HANDLE = "audAlertSignalHandle";
private static final String OTH_ALERT_SIGNAL_HANDLE = "othAlertSignalHandle";
private static final String TAN_ALERT_SIGNAL_HANDLE = "tanAlertSignalHandle";
@@ -188,7 +192,11 @@ void setUp() throws IOException {
mockMdibAccess = mock(MdibAccess.class, Answers.RETURNS_DEEP_STUBS);
mockTestClient = mock(TestClient.class, Answers.RETURNS_DEEP_STUBS);
+ final var clientInjector = TestClientUtil.createClientInjector();
when(mockTestClient.getSdcRemoteDevice()).thenReturn(mockDevice);
+ when(mockTestClient.isClientRunning()).thenReturn(true);
+ when(mockTestClient.getSdcRemoteDevice()).thenReturn(mockDevice);
+ when(mockTestClient.getInjector()).thenReturn(clientInjector);
injector = InjectorUtil.setupInjector(new AbstractModule() {
@Override
@@ -199,6 +207,7 @@ protected void configure() {
}
});
+ InjectorTestBase.setInjector(injector);
testRunObserver = injector.getInstance(TestRunObserver.class);
}
@@ -1897,4 +1906,279 @@ void testSystemSignalActivationSomeFail() {
assertFalse(ManipulationPreconditions.SystemSignalActivationManipulation.manipulation(injector));
}
+
+ @Test
+ @DisplayName("DescriptionModificationAllWithParentChildRelationshipPrecondition correctly calls manipulation")
+ void testDescriptionModificationAllWithParentChildRelationshipPreconditionManipulation() {
+
+ final var descriptor1Handle = "superHandle";
+ final var descriptor2Handle = "handle;Süper;";
+ final var parentDescriptorHandle = "parentHandle";
+ final var childDescriptorHandle = "childHandle";
+
+ final var presenceMap = new HashMap<>(Map.of(
+ descriptor1Handle, false,
+ descriptor2Handle, true));
+
+ when(mockManipulations.getRemovableDescriptorsOfClass())
+ .thenReturn(List.of(descriptor1Handle, descriptor2Handle));
+
+ when(mockManipulations.insertDescriptor(anyString())).thenAnswer((Answer) invocation -> {
+ presenceMap.put(invocation.getArgument(0), true);
+ return ResponseTypes.Result.RESULT_SUCCESS;
+ });
+ when(mockManipulations.removeDescriptor(anyString())).thenAnswer((Answer) invocation -> {
+ presenceMap.put(invocation.getArgument(0), false);
+ return ResponseTypes.Result.RESULT_SUCCESS;
+ });
+ when(mockManipulations.triggerDescriptorUpdate(anyList())).thenReturn(ResponseTypes.Result.RESULT_SUCCESS);
+ final MdibEntity mockEntityB2 = mock(MdibEntity.class);
+ when(mockEntityB2.getHandle()).thenReturn(parentDescriptorHandle);
+ when(mockEntityB2.getChildren()).thenReturn(List.of(childDescriptorHandle));
+ when(mockTestClient.getSdcRemoteDevice().getMdibAccess().findEntitiesByType(any()))
+ .thenReturn(List.of(mockEntityB2));
+ final MdibEntity mockEntityB3 = mock(MdibEntity.class);
+ when(mockTestClient.getSdcRemoteDevice().getMdibAccess().getEntity(any()))
+ .thenAnswer(args -> {
+ if (presenceMap.get((String) args.getArgument(0))) {
+ return Optional.of(mockEntityB3);
+ } else {
+ return Optional.empty();
+ }
+ });
+
+ assertTrue(
+ ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition
+ .manipulation(injector));
+
+ final var insertCaptor = ArgumentCaptor.forClass(String.class);
+ final var removeCaptor = ArgumentCaptor.forClass(String.class);
+ final var handleCaptor = ArgumentCaptor.forClass(List.class);
+ verify(mockManipulations, times(1)).getRemovableDescriptorsOfClass();
+ verify(mockManipulations, times(3)).insertDescriptor(insertCaptor.capture());
+ verify(mockManipulations, times(2)).removeDescriptor(removeCaptor.capture());
+ verify(mockManipulations, times(1)).triggerDescriptorUpdate(handleCaptor.capture());
+
+ assertEquals(2, handleCaptor.getAllValues().get(0).size());
+ assertEquals(childDescriptorHandle, handleCaptor.getAllValues().get(0).get(0));
+ assertEquals(parentDescriptorHandle, handleCaptor.getAllValues().get(0).get(1));
+
+ assertEquals(
+ 2,
+ insertCaptor.getAllValues().stream()
+ .filter(descriptor1Handle::equals)
+ .count());
+ assertEquals(
+ 1,
+ insertCaptor.getAllValues().stream()
+ .filter(descriptor2Handle::equals)
+ .count());
+
+ assertEquals(
+ 1,
+ removeCaptor.getAllValues().stream()
+ .filter(descriptor1Handle::equals)
+ .count());
+ assertEquals(
+ 1,
+ removeCaptor.getAllValues().stream()
+ .filter(descriptor2Handle::equals)
+ .count());
+ }
+
+ @Test
+ @DisplayName(
+ "DescriptionModificationAllWithParentChildRelationshipPrecondition when GetRemovableDescriptors failed.")
+ void
+ testDescriptionModificationAllWithParentChildRelationshipPreconditionManipulationGetRemovableDescriptorsFailed() {
+
+ final var descriptor1Handle = "superHandle";
+ final var descriptor2Handle = "handle;Süper;";
+ final var parentDescriptorHandle = "parentHandle";
+ final var childDescriptorHandle = "childHandle";
+
+ final var presenceMap = new HashMap<>(Map.of(
+ descriptor1Handle, false,
+ descriptor2Handle, true));
+
+ when(mockManipulations.getRemovableDescriptorsOfClass())
+ .thenReturn(List.of()); // When the manipulation is NOT_SUPPORTED, an empty list is returned.
+
+ when(mockManipulations.insertDescriptor(anyString())).thenAnswer((Answer) invocation -> {
+ presenceMap.put(invocation.getArgument(0), true);
+ return ResponseTypes.Result.RESULT_SUCCESS;
+ });
+ when(mockManipulations.removeDescriptor(anyString())).thenAnswer((Answer) invocation -> {
+ presenceMap.put(invocation.getArgument(0), false);
+ return ResponseTypes.Result.RESULT_SUCCESS;
+ });
+ when(mockManipulations.triggerDescriptorUpdate(anyList())).thenReturn(ResponseTypes.Result.RESULT_SUCCESS);
+ final MdibEntity mockEntityB = mock(MdibEntity.class);
+ when(mockEntityB.getHandle()).thenReturn(parentDescriptorHandle);
+ when(mockEntityB.getChildren()).thenReturn(List.of(childDescriptorHandle));
+ when(mockTestClient.getSdcRemoteDevice().getMdibAccess().findEntitiesByType(any()))
+ .thenReturn(List.of(mockEntityB));
+ final MdibEntity mockEntityB2 = mock(MdibEntity.class);
+ when(mockTestClient.getSdcRemoteDevice().getMdibAccess().getEntity(any()))
+ .thenAnswer(args -> {
+ if (presenceMap.get((String) args.getArgument(0))) {
+ return Optional.of(mockEntityB2);
+ } else {
+ return Optional.empty();
+ }
+ });
+
+ assertTrue(
+ ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition
+ .manipulation(injector));
+
+ final var handleCaptor = ArgumentCaptor.forClass(List.class);
+ verify(mockManipulations, times(1)).getRemovableDescriptorsOfClass();
+ verify(mockManipulations, times(0)).insertDescriptor(any());
+ verify(mockManipulations, times(0)).removeDescriptor(any());
+ verify(mockManipulations, times(1)).triggerDescriptorUpdate(handleCaptor.capture());
+
+ assertEquals(2, handleCaptor.getAllValues().get(0).size());
+ assertEquals(childDescriptorHandle, handleCaptor.getAllValues().get(0).get(0));
+ assertEquals(parentDescriptorHandle, handleCaptor.getAllValues().get(0).get(1));
+ }
+
+ @Test
+ @DisplayName(
+ "DescriptionModificationAllWithParentChildRelationshipPrecondition when TriggerDescriptorUpdate failed")
+ void testDescriptionModificationAllWithParentChildRelationshipPreconditionManipulationFailed2() {
+
+ final var descriptor1Handle = "superHandle";
+ final var descriptor2Handle = "handle;Süper;";
+ final var parentDescriptorHandle = "parentHandle";
+ final var childDescriptorHandle = "childHandle";
+
+ final var presenceMap = new HashMap<>(Map.of(
+ descriptor1Handle, false,
+ descriptor2Handle, true));
+
+ when(mockManipulations.getRemovableDescriptorsOfClass())
+ .thenReturn(List.of(descriptor1Handle, descriptor2Handle));
+
+ when(mockManipulations.insertDescriptor(anyString())).thenAnswer((Answer) invocation -> {
+ presenceMap.put(invocation.getArgument(0), true);
+ return ResponseTypes.Result.RESULT_SUCCESS;
+ });
+ when(mockManipulations.removeDescriptor(anyString())).thenAnswer((Answer) invocation -> {
+ presenceMap.put(invocation.getArgument(0), false);
+ return ResponseTypes.Result.RESULT_SUCCESS;
+ });
+ when(mockManipulations.triggerDescriptorUpdate(anyList())).thenReturn(ResponseTypes.Result.RESULT_FAIL);
+ final MdibEntity mockEntityB = mock(MdibEntity.class);
+ when(mockEntityB.getHandle()).thenReturn(parentDescriptorHandle);
+ when(mockEntityB.getChildren()).thenReturn(List.of(childDescriptorHandle));
+ when(mockTestClient.getSdcRemoteDevice().getMdibAccess().findEntitiesByType(any()))
+ .thenReturn(List.of(mockEntityB));
+ final MdibEntity mockEntityB2 = mock(MdibEntity.class);
+ when(mockTestClient.getSdcRemoteDevice().getMdibAccess().getEntity(any()))
+ .thenAnswer(args -> {
+ if (presenceMap.get((String) args.getArgument(0))) {
+ return Optional.of(mockEntityB2);
+ } else {
+ return Optional.empty();
+ }
+ });
+
+ assertTrue(
+ ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition
+ .manipulation(injector));
+
+ final var insertCaptor = ArgumentCaptor.forClass(String.class);
+ final var removeCaptor = ArgumentCaptor.forClass(String.class);
+ final var handleCaptor = ArgumentCaptor.forClass(List.class);
+ verify(mockManipulations, times(1)).getRemovableDescriptorsOfClass();
+ verify(mockManipulations, times(3)).insertDescriptor(insertCaptor.capture());
+ verify(mockManipulations, times(2)).removeDescriptor(removeCaptor.capture());
+ verify(mockManipulations, times(1)).triggerDescriptorUpdate(handleCaptor.capture());
+
+ assertEquals(2, handleCaptor.getAllValues().get(0).size());
+ assertEquals(childDescriptorHandle, handleCaptor.getAllValues().get(0).get(0));
+ assertEquals(parentDescriptorHandle, handleCaptor.getAllValues().get(0).get(1));
+
+ assertEquals(
+ 2,
+ insertCaptor.getAllValues().stream()
+ .filter(descriptor1Handle::equals)
+ .count());
+ assertEquals(
+ 1,
+ insertCaptor.getAllValues().stream()
+ .filter(descriptor2Handle::equals)
+ .count());
+
+ assertEquals(
+ 1,
+ removeCaptor.getAllValues().stream()
+ .filter(descriptor1Handle::equals)
+ .count());
+ assertEquals(
+ 1,
+ removeCaptor.getAllValues().stream()
+ .filter(descriptor2Handle::equals)
+ .count());
+ }
+
+ @Test
+ @DisplayName("DescriptionModificationAllWithParentChildRelationshipPrecondition when both GetRemovableDescriptors "
+ + "and TriggerDescriptorUpdate fail")
+ void testDescriptionModificationAllWithParentChildRelationshipPreconditionManipulationFailed3() {
+
+ final var descriptor1Handle = "superHandle";
+ final var descriptor2Handle = "handle;Süper;";
+ final var parentDescriptorHandle = "parentHandle";
+ final var childDescriptorHandle = "childHandle";
+
+ final var presenceMap = new HashMap<>(Map.of(
+ descriptor1Handle, false,
+ descriptor2Handle, true));
+
+ when(mockManipulations.getRemovableDescriptorsOfClass())
+ .thenReturn(List.of()); // When the manipulation returns RESULT_NOT_SUPPORTED, then an empty list
+ // is returned
+
+ when(mockManipulations.insertDescriptor(anyString())).thenAnswer((Answer) invocation -> {
+ presenceMap.put(invocation.getArgument(0), true);
+ return ResponseTypes.Result.RESULT_SUCCESS;
+ });
+ when(mockManipulations.removeDescriptor(anyString())).thenAnswer((Answer) invocation -> {
+ presenceMap.put(invocation.getArgument(0), false);
+ return ResponseTypes.Result.RESULT_SUCCESS;
+ });
+ when(mockManipulations.triggerDescriptorUpdate(anyList())).thenReturn(ResponseTypes.Result.RESULT_FAIL);
+ final MdibEntity mockEntityB = mock(MdibEntity.class);
+ when(mockEntityB.getHandle()).thenReturn(parentDescriptorHandle);
+ when(mockEntityB.getChildren()).thenReturn(List.of(childDescriptorHandle));
+ when(mockTestClient.getSdcRemoteDevice().getMdibAccess().findEntitiesByType(any()))
+ .thenReturn(List.of(mockEntityB));
+ final MdibEntity mockEntityB2 = mock(MdibEntity.class);
+ when(mockTestClient.getSdcRemoteDevice().getMdibAccess().getEntity(any()))
+ .thenAnswer(args -> {
+ if (presenceMap.get((String) args.getArgument(0))) {
+ return Optional.of(mockEntityB2);
+ } else {
+ return Optional.empty();
+ }
+ });
+
+ assertFalse(
+ ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition
+ .manipulation(injector));
+
+ final var insertCaptor = ArgumentCaptor.forClass(String.class);
+ final var removeCaptor = ArgumentCaptor.forClass(String.class);
+ final var handleCaptor = ArgumentCaptor.forClass(List.class);
+ verify(mockManipulations, times(1)).getRemovableDescriptorsOfClass();
+ verify(mockManipulations, times(0)).insertDescriptor(insertCaptor.capture());
+ verify(mockManipulations, times(0)).removeDescriptor(removeCaptor.capture());
+ verify(mockManipulations, times(1)).triggerDescriptorUpdate(handleCaptor.capture());
+
+ assertEquals(2, handleCaptor.getAllValues().get(0).size());
+ assertEquals(childDescriptorHandle, handleCaptor.getAllValues().get(0).get(0));
+ assertEquals(parentDescriptorHandle, handleCaptor.getAllValues().get(0).get(1));
+ }
}