This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git


The following commit(s) were added to refs/heads/master by this push:
     new 292474b  improved AdsAbstractPlcConnectionTest and refined 
Junit5Backport method.
292474b is described below

commit 292474b2e60186f813346162d87764bd83e24c56
Author: Sebastian Rühl <sru...@apache.org>
AuthorDate: Wed May 30 10:45:41 2018 +0200

    improved AdsAbstractPlcConnectionTest and refined Junit5Backport method.
---
 .../ads/connection/AdsAbstractPlcConnection.java   |   7 +
 .../connection/AdsAbstractPlcConnectionTest.java   | 200 ++++++++++++++++++---
 .../apache/plc4x/java/ads/util/Junit5Backport.java |   2 +-
 3 files changed, 187 insertions(+), 22 deletions(-)

diff --git 
a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
 
b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
index 5e0d647..2304199 100644
--- 
a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
+++ 
b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
@@ -204,6 +204,13 @@ public abstract class AdsAbstractPlcConnection extends 
AbstractPlcConnection imp
         super.close();
     }
 
+    /**
+     * Clears the addressMapping.
+     */
+    public void clearMapping() {
+        addressMapping.clear();
+    }
+
     protected <T> T getFromFuture(CompletableFuture<T> future, long timeout) {
         try {
             return future.get(timeout, TimeUnit.MILLISECONDS);
diff --git 
a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnectionTest.java
 
b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnectionTest.java
index de5c77d..8b274fa 100644
--- 
a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnectionTest.java
+++ 
b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnectionTest.java
@@ -21,12 +21,17 @@ package org.apache.plc4x.java.ads.connection;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelHandler;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.plc4x.java.ads.api.commands.AdsReadWriteResponse;
 import org.apache.plc4x.java.ads.api.commands.types.Data;
 import org.apache.plc4x.java.ads.api.commands.types.Result;
 import org.apache.plc4x.java.ads.api.generic.types.AmsNetId;
 import org.apache.plc4x.java.ads.api.generic.types.AmsPort;
+import org.apache.plc4x.java.ads.model.AdsAddress;
 import org.apache.plc4x.java.ads.model.SymbolicAdsAddress;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.api.messages.specific.TypeSafePlcReadRequest;
 import org.apache.plc4x.java.api.messages.specific.TypeSafePlcReadResponse;
@@ -36,20 +41,38 @@ import org.apache.plc4x.java.api.model.Address;
 import org.apache.plc4x.java.base.connection.ChannelFactory;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import java.util.concurrent.CompletableFuture;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.*;
 
-import static org.junit.Assert.assertNotNull;
+import static org.apache.plc4x.java.ads.util.Junit5Backport.assertThrows;
+import static org.junit.Assert.*;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.*;
 
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
 public class AdsAbstractPlcConnectionTest {
 
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(AdsAbstractPlcConnectionTest.class);
+
     private AdsAbstractPlcConnection SUT;
 
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private ChannelFactory channelFactory;
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Channel channel;
+
     @Before
     public void setUp() throws Exception {
-        ChannelFactory channelFactory = mock(ChannelFactory.class, 
RETURNS_DEEP_STUBS);
         SUT = new AdsAbstractPlcConnection(channelFactory, 
mock(AmsNetId.class), mock(AmsPort.class), mock(AmsNetId.class), 
mock(AmsPort.class)) {
             @Override
             protected ChannelHandler getChannelHandler(CompletableFuture<Void> 
sessionSetupCompleteFuture) {
@@ -57,24 +80,24 @@ public class AdsAbstractPlcConnectionTest {
             }
         };
 
-        // Specific to mapAddress
-        Channel channel = mock(Channel.class, RETURNS_DEEP_STUBS);
         when(channelFactory.createChannel(any())).thenReturn(channel);
-        
when(channel.writeAndFlush(any(PlcRequestContainer.class))).then(invocation -> {
-            PlcRequestContainer plcRequestContainer = 
invocation.getArgument(0);
-            PlcProprietaryResponse plcProprietaryResponse = 
mock(PlcProprietaryResponse.class, RETURNS_DEEP_STUBS);
-            AdsReadWriteResponse adsReadWriteResponse = 
mock(AdsReadWriteResponse.class, RETURNS_DEEP_STUBS);
-            when(adsReadWriteResponse.getResult()).thenReturn(Result.of(0));
-            when(adsReadWriteResponse.getData()).thenReturn(Data.of(new 
byte[]{1, 2, 3, 4}));
-            
when(plcProprietaryResponse.getResponse()).thenReturn(adsReadWriteResponse);
-            
plcRequestContainer.getResponseFuture().complete(plcProprietaryResponse);
-            return mock(ChannelFuture.class);
-        });
 
         SUT.connect();
     }
 
     @Test
+    public void lazyConstructor() {
+        AdsAbstractPlcConnection constructed = new 
AdsAbstractPlcConnection(channelFactory, mock(AmsNetId.class), 
mock(AmsPort.class)) {
+            @Override
+            protected ChannelHandler getChannelHandler(CompletableFuture<Void> 
sessionSetupCompleteFuture) {
+                return null;
+            }
+        };
+        assertEquals(AdsAbstractPlcConnection.generateAMSNetId(), 
constructed.getSourceAmsNetId());
+        assertEquals(AdsAbstractPlcConnection.generateAMSPort(), 
constructed.getSourceAmsPort());
+    }
+
+    @Test
     public void getTargetAmsNetId() {
         AmsNetId targetAmsNetId = SUT.getTargetAmsNetId();
         assertNotNull(targetAmsNetId);
@@ -112,6 +135,9 @@ public class AdsAbstractPlcConnectionTest {
         assertNotNull(read);
         CompletableFuture<TypeSafePlcReadResponse<Object>> typeSafeRead = 
SUT.read(mock(TypeSafePlcReadRequest.class));
         assertNotNull(typeSafeRead);
+
+        simulatePipelineError(() -> SUT.read(mock(PlcReadRequest.class)));
+        simulatePipelineError(() -> 
SUT.read(mock(TypeSafePlcReadRequest.class)));
     }
 
     @Test
@@ -120,12 +146,43 @@ public class AdsAbstractPlcConnectionTest {
         assertNotNull(write);
         CompletableFuture<TypeSafePlcWriteResponse<Object>> typeSafeWrite = 
SUT.write(mock(TypeSafePlcWriteRequest.class));
         assertNotNull(typeSafeWrite);
+
+        simulatePipelineError(() -> SUT.write(mock(PlcWriteRequest.class)));
+        simulatePipelineError(() -> 
SUT.write(mock(TypeSafePlcWriteRequest.class)));
     }
 
     @Test
     public void send() {
         CompletableFuture send = SUT.send(mock(PlcProprietaryRequest.class));
         assertNotNull(send);
+
+        simulatePipelineError(() -> 
SUT.send(mock(PlcProprietaryRequest.class)));
+    }
+
+    public void simulatePipelineError(FutureProducingTestRunnable 
futureProducingTestRunnable) {
+        ChannelFuture channelFuture = mock(ChannelFuture.class);
+        // Simulate error in the pipeline
+        when(channelFuture.addListener(any())).thenAnswer(invocation -> {
+            Future future = mock(Future.class);
+            when(future.isSuccess()).thenReturn(false);
+            when(future.cause()).thenReturn(new DummyException());
+            GenericFutureListener genericFutureListener = 
invocation.getArgument(0);
+            genericFutureListener.operationComplete(future);
+            return mock(ChannelFuture.class);
+        });
+        when(channel.writeAndFlush(any())).thenReturn(channelFuture);
+        assertThrows(DummyException.class, () -> {
+            CompletableFuture completableFuture = 
futureProducingTestRunnable.run();
+            try {
+                completableFuture.get(3, TimeUnit.SECONDS);
+                fail("Should have thrown a ExecutionException");
+            } catch (ExecutionException e) {
+                if (e.getCause() instanceof DummyException) {
+                    throw (DummyException) e.getCause();
+                }
+                throw e;
+            }
+        });
     }
 
     @Test
@@ -135,12 +192,47 @@ public class AdsAbstractPlcConnectionTest {
 
     @Test
     public void mapAddress() {
-        SUT.mapAddress(SymbolicAdsAddress.of("Main.byByte[0]"));
+        // positive
+        {
+            
when(channel.writeAndFlush(any(PlcRequestContainer.class))).then(invocation -> {
+                PlcRequestContainer plcRequestContainer = 
invocation.getArgument(0);
+                PlcProprietaryResponse plcProprietaryResponse = 
mock(PlcProprietaryResponse.class, RETURNS_DEEP_STUBS);
+                AdsReadWriteResponse adsReadWriteResponse = 
mock(AdsReadWriteResponse.class, RETURNS_DEEP_STUBS);
+                
when(adsReadWriteResponse.getResult()).thenReturn(Result.of(0));
+                when(adsReadWriteResponse.getData()).thenReturn(Data.of(new 
byte[]{1, 2, 3, 4}));
+                
when(plcProprietaryResponse.getResponse()).thenReturn(adsReadWriteResponse);
+                
plcRequestContainer.getResponseFuture().complete(plcProprietaryResponse);
+                return mock(ChannelFuture.class);
+            });
+
+            SUT.mapAddress(SymbolicAdsAddress.of("Main.byByte[0]"));
+            SUT.mapAddress(SymbolicAdsAddress.of("Main.byByte[0]"));
+            verify(channel, 
times(1)).writeAndFlush(any(PlcRequestContainer.class));
+            SUT.clearMapping();
+            reset(channel);
+        }
+        // negative
+        {
+            
when(channel.writeAndFlush(any(PlcRequestContainer.class))).then(invocation -> {
+                PlcRequestContainer plcRequestContainer = 
invocation.getArgument(0);
+                PlcProprietaryResponse plcProprietaryResponse = 
mock(PlcProprietaryResponse.class, RETURNS_DEEP_STUBS);
+                AdsReadWriteResponse adsReadWriteResponse = 
mock(AdsReadWriteResponse.class, RETURNS_DEEP_STUBS);
+                
when(adsReadWriteResponse.getResult()).thenReturn(Result.of(1));
+                
when(plcProprietaryResponse.getResponse()).thenReturn(adsReadWriteResponse);
+                
plcRequestContainer.getResponseFuture().complete(plcProprietaryResponse);
+                return mock(ChannelFuture.class);
+            });
+
+            assertThrows(PlcRuntimeException.class, () -> 
SUT.mapAddress(SymbolicAdsAddress.of("Main.byByte[0]")));
+            verify(channel, 
times(1)).writeAndFlush(any(PlcRequestContainer.class));
+            SUT.clearMapping();
+            reset(channel);
+        }
     }
 
     @Test
     public void generateAMSNetId() {
-        AmsNetId targetAmsNetId = SUT.getTargetAmsNetId();
+        AmsNetId targetAmsNetId = AdsAbstractPlcConnection.generateAMSNetId();
         assertNotNull(targetAmsNetId);
     }
 
@@ -151,14 +243,60 @@ public class AdsAbstractPlcConnectionTest {
     }
 
     @Test
-    public void close() {
+    public void close() throws Exception {
+        Map addressMapping = (Map) 
FieldUtils.getDeclaredField(AdsAbstractPlcConnection.class, "addressMapping", 
true).get(SUT);
+        addressMapping.put(mock(SymbolicAdsAddress.class), 
mock(AdsAddress.class));
         SUT.close();
     }
 
     @Test
-    public void getFromFuture() {
-        Object fromFuture = SUT.getFromFuture(mock(CompletableFuture.class, 
RETURNS_DEEP_STUBS), 1);
-        assertNotNull(fromFuture);
+    public void getFromFuture() throws Exception {
+        runInThread(() -> {
+            CompletableFuture completableFuture = 
mock(CompletableFuture.class, RETURNS_DEEP_STUBS);
+            Object fromFuture = SUT.getFromFuture(completableFuture, 1);
+            assertNotNull(fromFuture);
+        });
+        runInThread(() -> {
+            CompletableFuture completableFuture = 
mock(CompletableFuture.class, RETURNS_DEEP_STUBS);
+            when(completableFuture.get(anyLong(), 
any())).thenThrow(InterruptedException.class);
+            assertThrows(PlcRuntimeException.class, () -> 
SUT.getFromFuture(completableFuture, 1));
+        });
+        runInThread(() -> {
+            CompletableFuture completableFuture = 
mock(CompletableFuture.class, RETURNS_DEEP_STUBS);
+            when(completableFuture.get(anyLong(), 
any())).thenThrow(ExecutionException.class);
+            assertThrows(PlcRuntimeException.class, () -> 
SUT.getFromFuture(completableFuture, 1));
+        });
+        runInThread(() -> {
+            CompletableFuture completableFuture = 
mock(CompletableFuture.class, RETURNS_DEEP_STUBS);
+            when(completableFuture.get(anyLong(), 
any())).thenThrow(TimeoutException.class);
+            assertThrows(PlcRuntimeException.class, () -> 
SUT.getFromFuture(completableFuture, 1));
+        });
+        assertFalse("The current Thread should not be interrupted", 
Thread.currentThread().isInterrupted());
+    }
+
+    /**
+     * Runs tests steps in a dedicated {@link Thread} so a possible {@link 
InterruptedException} doesn't lead to a
+     * interrupt flag being set on the main Thread ({@see 
Thread.currentThread().isInterrupted()}).
+     *
+     * @param testRunnable a special {@link Runnable} which adds a {@code 
throws Exception} to the {@code run} signature.
+     * @throws InterruptedException when this {@link Thread} gets interrupted.
+     */
+    public void runInThread(TestRunnable testRunnable) throws 
InterruptedException {
+        Thread thread = new Thread(() -> {
+            try {
+                testRunnable.run();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        });
+        Queue<Throwable> uncaughtExceptions = new ConcurrentLinkedQueue<>();
+        thread.setUncaughtExceptionHandler((t, e) -> 
uncaughtExceptions.add(e));
+        thread.start();
+        thread.join();
+        if (!uncaughtExceptions.isEmpty()) {
+            uncaughtExceptions.forEach(throwable -> LOGGER.error("Assertion 
Error: Unexpected Exception", throwable));
+            throw new AssertionError("Test failures. Check log");
+        }
     }
 
     @Test
@@ -166,4 +304,24 @@ public class AdsAbstractPlcConnectionTest {
         String s = SUT.toString();
         assertNotNull(s);
     }
+
+    /**
+     * Variant of {@link Runnable} which adds a {@code throws Exception} to 
the {@code run} signature.
+     */
+    private interface TestRunnable {
+        /**
+         * @throws Exception when the test throws a exception.
+         * @see Runnable#run()
+         */
+        void run() throws Exception;
+    }
+
+    private static class DummyException extends Exception {
+
+    }
+
+    @FunctionalInterface
+    private interface FutureProducingTestRunnable {
+        CompletableFuture run() throws Exception;
+    }
 }
\ No newline at end of file
diff --git 
a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/util/Junit5Backport.java
 
b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/util/Junit5Backport.java
index 34d8783..973c351 100644
--- 
a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/util/Junit5Backport.java
+++ 
b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/util/Junit5Backport.java
@@ -25,7 +25,7 @@ public class Junit5Backport {
             acceptor.accept();
         } catch (Exception e) {
             if (!exception.isAssignableFrom(e.getClass())) {
-                throw new RuntimeException(e);
+                throw new AssertionError("Unexpected exception type " + 
e.getClass() + ". Expected " + exception, e);
             }
         }
     }

-- 
To stop receiving notification emails like this one, please contact
sru...@apache.org.

Reply via email to