From b5467e87c5a9c2037186a980109616483d51b33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Engelmann?= Date: Fri, 9 Feb 2024 17:39:54 +0100 Subject: [PATCH] Fixed Defect in Test Case for Glue:R0036_0. --- .../DirectSubscriptionHandlingTest.java | 12 +- .../DirectSubscriptionHandlingTestTest.java | 141 ++++++++++++++---- 2 files changed, 124 insertions(+), 29 deletions(-) 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..4edf2f68 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 @@ -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,15 @@ 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. + result = null; + } 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..2d844b9b 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 @@ -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,31 @@ 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 +573,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 +590,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 +607,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 +624,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 +641,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 +658,7 @@ 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 +671,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 +689,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 +708,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 +727,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, + boolean faultOnUnsupportedSubscription) throws Exception { testDeviceForR00360( expectFailure, delayBeforeCancellingInSeconds, sendSubscriptionEnd, subscriptionEndStatus, + faultOnUnsupportedSubscription, AssertionError.class); } @@ -731,10 +762,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 +799,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 +879,19 @@ private void setupTestScenarioForR00360( lastSubscriptionId.addAndGet(1); return createListenableFuture(new SubscribeResult(subscriptionId, Duration.ofSeconds(60))); } else { - return createListenableFuture(null); + if (faultOnUnsupportedSubscription) { + var unsupportedActions = actions.stream().filter((action) -> + !this.supportedReports.contains(action) + ).toList(); + var message = soapFaultFactory.createReceiverFault( + String.join(", ", unsupportedActions) + " not supported"); + var e = new SoapFaultException(message); + return createListenableFutureThatExecutes(() -> { + throw new ExecutionException(e); + }); + } else { + return createListenableFuture(null); + } } }); @@ -987,6 +1037,43 @@ public T get(final long timeout, final TimeUnit unit) { }; } + interface CallbackReturningT { + T execute() throws ExecutionException; + } + + private ListenableFuture createListenableFutureThatExecutes(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);