Skip to content

Commit

Permalink
Fixed Defect in Test case for Biceps:R5025 (#125)
Browse files Browse the repository at this point in the history
The Requirement Biceps:R5025 applies to all
DescriptionModificationReports. However, the Precondition of its SDCcc
Test case could only trigger Crt and Del ReportParts. Hence, when a
Device only support Upt ReportParts in DescriptionModificationReports
then the Requirement is applicable to it, but it cannot satisfy the test
case.

This PR solves this problem by letting the Test case use another
Precondition that tries to trigger DescriptionModificationReports with
Crt, Del and Upt ReportParts.

# Checklist

The following aspects have been respected by the author of this pull
request, confirmed by both pull request assignee **and** reviewer:

* Adherence to coding conventions
  * [x] Pull Request Assignee
  * [x] Reviewer
* Adherence to javadoc conventions
  * [x] Pull Request Assignee
  * [x] Reviewer
* Changelog update (necessity checked and entry added or not added
respectively)
  * [x] Pull Request Assignee
  * [x] Reviewer
* README update (necessity checked and entry added or not added
respectively)
  * [x] Pull Request Assignee
  * [x] Reviewer
* config update (necessity checked and entry added or not added
respectively)
  * [x] Pull Request Assignee
  * [x] Reviewer
* SDCcc executable ran against a test device (if necessary)
  * [x] Pull Request Assignee
  * [x] Reviewer
  • Loading branch information
ben-Draeger authored Sep 11, 2023
1 parent 539ca24 commit 3154c06
Show file tree
Hide file tree
Showing 14 changed files with 496 additions and 81 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
2 changes: 1 addition & 1 deletion sdccc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@
<dependency>
<groupId>com.draeger.medical</groupId>
<artifactId>t2iapi</artifactId>
<version>3.0.0.262</version>
<version>3.0.0.296</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,19 @@ public void close() {}
return interactionResult ? ResponseTypes.Result.RESULT_SUCCESS : ResponseTypes.Result.RESULT_FAIL;
}

@Override
public ResponseTypes.Result triggerDescriptorUpdate(final List<String> 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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> handles);

/**
* Trigger a descriptor update for some descriptor (chosen by the device).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<ResponseTypes.Result>();
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<String, String> 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<String, String> 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<MdibEntity> 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<String> children = entity.getChildren();
if (!children.isEmpty()) {
return Pair.of(entity.getHandle(), children.get(0));
}
}
return null;
}

/**
* Associates two <em>new</em> patients for every available PatientContextDescriptor present in the provider mdib.
*/
Expand Down Expand Up @@ -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<ResponseTypes.Result>();
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;
}
}
}
Loading

0 comments on commit 3154c06

Please sign in to comment.