From bbdc6c39be71708ec87fd3f53ea7d79ad5a320a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn?= Date: Mon, 19 Feb 2024 12:58:34 +0100 Subject: [PATCH] Fixed Defect in Test Case for Glue:R0036_0. (#136) Fixed defect in test case for Glue:R0036_0. # 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 --------- Co-authored-by: Maximilian Pilz --- CHANGELOG.md | 1 + .../DirectSubscriptionHandlingTest.java | 16 +- .../DirectSubscriptionHandlingTestTest.java | 137 ++++++++++++++---- 3 files changed, 123 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2707d58..cfe08dd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - local address resolver sometimes giving a wrong address - local address resolver doing a probe which may not be tolerated by some peers - potential NullPointerException in DescriptionModificationUptPrecondition +- the test case for Glue:R0036_0 not accepting a SOAPFault as a valid answer for Subscribe messages ## [8.0.1] - 2023-09-13 diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/glue/direct/DirectSubscriptionHandlingTest.java b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/glue/direct/DirectSubscriptionHandlingTest.java index 3f76f318..dd8d12a0 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/glue/direct/DirectSubscriptionHandlingTest.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/glue/direct/DirectSubscriptionHandlingTest.java @@ -1,6 +1,6 @@ /* * This Source Code Form is subject to the terms of the MIT License. - * Copyright (c) 2023 Draegerwerk AG & Co. KGaA. + * Copyright (c) 2023, 2024 Draegerwerk AG & Co. KGaA. * * SPDX-License-Identifier: MIT */ @@ -145,7 +145,7 @@ void testRequirementR0034() { final var hostedServices = testClient.getHostingServiceProxy().getHostedServices(); final var serviceIds = hostedServices.values().stream() .map(hostedServiceProxy -> hostedServiceProxy.getType().getServiceId()) - .collect(Collectors.toList()); + .toList(); if (hostedServices.values().size() != new HashSet<>(serviceIds).size()) { fail(String.format("Some Hosted Services share the same service id: %s, test failed.", serviceIds)); } @@ -596,7 +596,17 @@ public void onNotification(final NotificationObject message) { reportTestData.setSubscription(result); reportTestData.setEventSink(eventSink); } catch (InterruptedException | ExecutionException e) { - fail("encountered exception while subscribing to " + reportTestData.getReportName(), e); + if (e instanceof ExecutionException && e.getCause() instanceof SoapFaultException) { + // according to WS-Eventing, answering a Subscribe with a SOAPFault is a normal way of + // declining a subscription. We hence interpret it as "Report is not supported" and do + // not fail the test case. + LOG.warn( + "Subscription was answered by SOAPFault. The Device seems not to support " + + reportTestData.getReportName(), + e); + } else { + fail("encountered exception while subscribing to " + reportTestData.getReportName(), e); + } } return result; } diff --git a/sdccc/src/test/java/com/draeger/medical/sdccc/tests/glue/direct/DirectSubscriptionHandlingTestTest.java b/sdccc/src/test/java/com/draeger/medical/sdccc/tests/glue/direct/DirectSubscriptionHandlingTestTest.java index 80123df3..33db11fd 100644 --- a/sdccc/src/test/java/com/draeger/medical/sdccc/tests/glue/direct/DirectSubscriptionHandlingTestTest.java +++ b/sdccc/src/test/java/com/draeger/medical/sdccc/tests/glue/direct/DirectSubscriptionHandlingTestTest.java @@ -1,6 +1,6 @@ /* * This Source Code Form is subject to the terms of the MIT License. - * Copyright (c) 2023 Draegerwerk AG & Co. KGaA. + * Copyright (c) 2023, 2024 Draegerwerk AG & Co. KGaA. * * SPDX-License-Identifier: MIT */ @@ -50,6 +50,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -357,7 +358,7 @@ public void testRequirementR00360Good() throws Exception { ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -376,7 +377,7 @@ public void testRequirementR00360GoodNoLocationContext() throws Exception { ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - setupTestScenarioForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + setupTestScenarioForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); cancelledReports = new HashSet<>(); testUnderTest.testRequirementR00360(); @@ -398,7 +399,7 @@ public void testRequirementR00360BadTooManyCancelledSubscriptionsOperationInvoke ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -418,7 +419,7 @@ public void testRequirementR00360BadTooManyCancelledSubscriptionsDescriptionModi ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -437,7 +438,7 @@ public void testRequirementR00360BadTooManyCancelledSubscriptionsEpisodicAlertRe ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -456,7 +457,7 @@ public void testRequirementR00360BadTooManyCancelledSubscriptionsEpisodicCompone ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -475,7 +476,7 @@ public void testRequirementR00360BadTooManyCancelledSubscriptionsEpisodicMetricR ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -495,7 +496,7 @@ public void testRequirementR00360BadTooManyCancelledSubscriptionsEpisodicOperati ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -512,7 +513,7 @@ public void testRequirementR0036NoSupportForEpisodicAlertReport() throws Excepti ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } // NOTE: the test does not work when the Device does not support EpisodicContextReport. @@ -531,7 +532,25 @@ public void testRequirementR00360NoSupportForOperationInvokedReport() throws Exc ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); + } + + /** + * Tests whether a device that indicates that it does not support the OperationInvokedReport + * by sending a SOAPFault can still pass the test. + */ + @Test + public void testRequirementR00360GoodNoSupportForOperationInvokedReportSOAPFault() throws Exception { + reportsToCancel = new HashSet<>(Set.of(ActionConstants.ACTION_EPISODIC_CONTEXT_REPORT)); + supportedReports = new HashSet<>(Set.of( + ActionConstants.ACTION_EPISODIC_CONTEXT_REPORT, + ActionConstants.ACTION_DESCRIPTION_MODIFICATION_REPORT, + ActionConstants.ACTION_EPISODIC_ALERT_REPORT, + ActionConstants.ACTION_EPISODIC_COMPONENT_REPORT, + ActionConstants.ACTION_EPISODIC_METRIC_REPORT, + ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, + ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); + testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, true); } /** @@ -548,7 +567,7 @@ public void testRequirementR0036NoSupportForDescriptionModificationReport() thro ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -565,7 +584,7 @@ public void testRequirementR00360NoSupportForDescriptionModificationReport() thr ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -582,7 +601,7 @@ public void testRequirementR0036NoSupportForEpisodicComponentReport() throws Exc ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -599,7 +618,7 @@ public void testRequirementR00360NoSupportForEpisodicMetricReport() throws Excep ActionConstants.ACTION_EPISODIC_COMPONENT_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -616,7 +635,7 @@ public void testRequirementR00360NoSupportForEpisodicOperationalStateReport() th ActionConstants.ACTION_EPISODIC_COMPONENT_REPORT, ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(false, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -633,7 +652,8 @@ public void testRequirementR0036NoSupportForSystemErrorReport() throws Exception ActionConstants.ACTION_EPISODIC_COMPONENT_REPORT, ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT)); - testDeviceForR00360(false, INSIGNIFICANT_DELAY_IN_SECONDS, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360( + false, INSIGNIFICANT_DELAY_IN_SECONDS, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -646,7 +666,7 @@ public void testRequirementR0036NoSupportForSystemErrorReport() throws Exception public void testRequirementR00360NoReports() throws Exception { reportsToCancel = new HashSet<>(Set.of(ActionConstants.ACTION_EPISODIC_CONTEXT_REPORT)); supportedReports = new HashSet<>(Set.of()); - testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, NoTestData.class); + testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false, NoTestData.class); } /** @@ -664,7 +684,7 @@ public void testRequirementR00360WithStronglyDelayedCancellations() throws Excep ActionConstants.ACTION_EPISODIC_METRIC_REPORT, ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(true, SIGNIFICANT_DELAY_IN_SECONDS, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(true, SIGNIFICANT_DELAY_IN_SECONDS, true, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -683,7 +703,7 @@ public void testRequirementR00360BadSilentCancellation() throws Exception { ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(true, 0, false, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED); + testDeviceForR00360(true, 0, false, SUBSCRIPTION_END_STATUS_DELIVERY_FAILED, false); } /** @@ -702,27 +722,33 @@ public void testRequirementR00360BadCancellationWrongStatus() throws Exception { ActionConstants.ACTION_EPISODIC_OPERATIONAL_STATE_REPORT, ActionConstants.ACTION_SYSTEM_ERROR_REPORT)); - testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_CANCELLED); + testDeviceForR00360(true, 0, true, SUBSCRIPTION_END_STATUS_CANCELLED, false); } /** * Does all the work for the Tests for Requirement R0036_0. - * @param expectFailure - should the test expect Failure? + * + * @param expectFailure - should the test expect Failure? * @param delayBeforeCancellingInSeconds - time (in seconds) to wait before cancelling the subscriptions. - * @param sendSubscriptionEnd - true if a SubscriptionEnd Message should be send when a subscription is cancelled, - * @param subscriptionEndStatus - Status to set in the SubscriptionEnd message. + * @param sendSubscriptionEnd - true if a SubscriptionEnd Message should be send when a subscription is cancelled, + * @param subscriptionEndStatus - Status to set in the SubscriptionEnd message. + * @param faultOnUnsupportedSubscription - should an unsupported Subscription be answered with a SOAPFault? + * when false, the subscription is answered with an empty + * SubscriptionResponse instead. */ private void testDeviceForR00360( final boolean expectFailure, final int delayBeforeCancellingInSeconds, final boolean sendSubscriptionEnd, - final String subscriptionEndStatus) + final String subscriptionEndStatus, + final boolean faultOnUnsupportedSubscription) throws Exception { testDeviceForR00360( expectFailure, delayBeforeCancellingInSeconds, sendSubscriptionEnd, subscriptionEndStatus, + faultOnUnsupportedSubscription, AssertionError.class); } @@ -731,10 +757,16 @@ private void testDeviceForR00360( final int delayBeforeCancellingInSeconds, final boolean sendSubscriptionEnd, final String subscriptionEndStatus, + final boolean faultOnUnsupportedSubscription, final Class exceptionClass) throws Exception { // given - setupTestScenarioForR00360(true, delayBeforeCancellingInSeconds, sendSubscriptionEnd, subscriptionEndStatus); + setupTestScenarioForR00360( + true, + delayBeforeCancellingInSeconds, + sendSubscriptionEnd, + subscriptionEndStatus, + faultOnUnsupportedSubscription); this.cancelledReports = new HashSet<>(); // when & then @@ -762,7 +794,8 @@ private void setupTestScenarioForR00360( final boolean hasLocationContextState, final int delayBeforeCancellingInSeconds, final boolean sendSubscriptionEnd, - final String subscriptionEndStatus) + final String subscriptionEndStatus, + final boolean faultOnUnsupportedSubscription) throws Exception { final Map hostedServices = new HashMap<>(); @@ -841,7 +874,19 @@ private void setupTestScenarioForR00360( lastSubscriptionId.addAndGet(1); return createListenableFuture(new SubscribeResult(subscriptionId, Duration.ofSeconds(60))); } else { - return createListenableFuture(null); + if (faultOnUnsupportedSubscription) { + final var unsupportedActions = actions.stream() + .filter((action) -> !this.supportedReports.contains(action)) + .toList(); + final var message = soapFaultFactory.createReceiverFault( + String.join(", ", unsupportedActions) + " not supported"); + final var e = new SoapFaultException(message); + return createListenableFutureThatExecutes(() -> { + throw new ExecutionException(e); + }); + } else { + return createListenableFuture(null); + } } }); @@ -987,6 +1032,38 @@ public T get(final long timeout, final TimeUnit unit) { }; } + private ListenableFuture createListenableFutureThatExecutes(final CallbackReturningT callback) { + return new ListenableFuture<>() { + @Override + public void addListener(final Runnable runnable, final Executor executor) {} + + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return false; + } + + @Override + public T get() throws ExecutionException { + return callback.execute(); + } + + @Override + public T get(final long timeout, final TimeUnit unit) throws ExecutionException { + return get(); + } + }; + } + private HostedServiceProxy setupServiceMock( final QName portTypeContextQname, final RequestResponseClient requestResponseClient) { final HostedServiceProxy service = mock(HostedServiceProxy.class); @@ -997,6 +1074,10 @@ private HostedServiceProxy setupServiceMock( return service; } + interface CallbackReturningT { + T execute() throws ExecutionException; + } + /** * Calls all ReportInterceptors with an EpisodicContextReport and - if one of them throws an Exception, * waits for the given delay to pass and then delivers a SubscriptionEnd Message to all SubscriptionEndInterceptors.