]> git.basschouten.com Git - openhab-addons.git/blob
456dae30e2edd83977909b95980d00c52a940e46
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.dsmr.internal.device;
14
15 import static org.junit.Assert.*;
16 import static org.mockito.ArgumentMatchers.*;
17 import static org.mockito.Mockito.*;
18 import static org.mockito.MockitoAnnotations.initMocks;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.TooManyListenersException;
24 import java.util.concurrent.ScheduledExecutorService;
25 import java.util.concurrent.atomic.AtomicReference;
26 import java.util.stream.Stream;
27
28 import org.junit.Before;
29 import org.junit.Test;
30 import org.mockito.Mock;
31 import org.openhab.binding.dsmr.internal.DSMRBindingConstants;
32 import org.openhab.binding.dsmr.internal.TelegramReaderUtil;
33 import org.openhab.binding.dsmr.internal.device.DSMRSerialAutoDevice.DeviceState;
34 import org.openhab.binding.dsmr.internal.device.connector.DSMRConnectorErrorEvent;
35 import org.openhab.binding.dsmr.internal.device.p1telegram.P1Telegram;
36 import org.openhab.core.io.transport.serial.PortInUseException;
37 import org.openhab.core.io.transport.serial.SerialPort;
38 import org.openhab.core.io.transport.serial.SerialPortEvent;
39 import org.openhab.core.io.transport.serial.SerialPortEventListener;
40 import org.openhab.core.io.transport.serial.SerialPortIdentifier;
41 import org.openhab.core.io.transport.serial.SerialPortManager;
42
43 /**
44  * Test class for {@link DSMRSerialAutoDevice}.
45  *
46  * @author Hilbrand Bouwkamp - Initial contribution
47  */
48 public class DSMRSerialAutoDeviceTest {
49
50     private static final String DUMMY_PORTNAME = "/dev/dummy-serial";
51     private static final String TELEGRAM_NAME = "dsmr_50";
52
53     @Mock
54     private SerialPortIdentifier mockIdentifier;
55     @Mock
56     private ScheduledExecutorService scheduler;
57     @Mock
58     private SerialPort mockSerialPort;
59
60     private SerialPortManager serialPortManager = new SerialPortManager() {
61         @Override
62         public SerialPortIdentifier getIdentifier(String name) {
63             assertEquals("Expect the passed serial port name", DUMMY_PORTNAME, name);
64             return mockIdentifier;
65         }
66
67         @Override
68         public Stream<SerialPortIdentifier> getIdentifiers() {
69             return Stream.empty();
70         }
71     };
72     private SerialPortEventListener serialPortEventListener;
73
74     @Before
75     public void setUp() throws PortInUseException, TooManyListenersException {
76         initMocks(this);
77         doAnswer(a -> {
78             serialPortEventListener = a.getArgument(0);
79             return null;
80         }).when(mockSerialPort).addEventListener(any());
81     }
82
83     @Test
84     public void testHandlingDataAndRestart() throws IOException, PortInUseException {
85         mockValidSerialPort();
86         AtomicReference<P1Telegram> telegramRef = new AtomicReference<>(null);
87         DSMREventListener listener = new DSMREventListener() {
88             @Override
89             public void handleTelegramReceived(P1Telegram telegram) {
90                 telegramRef.set(telegram);
91             }
92
93             @Override
94             public void handleErrorEvent(DSMRConnectorErrorEvent connectorErrorEvent) {
95                 fail("No handleErrorEvent Expected" + connectorErrorEvent);
96             }
97         };
98         try (InputStream inputStream = new ByteArrayInputStream(TelegramReaderUtil.readRawTelegram(TELEGRAM_NAME))) {
99             when(mockSerialPort.getInputStream()).thenReturn(inputStream);
100             DSMRSerialAutoDevice device = new DSMRSerialAutoDevice(serialPortManager, DUMMY_PORTNAME, listener,
101                     new DSMRTelegramListener(), scheduler, 1);
102             device.start();
103             assertSame("Expect to be starting discovery state", DeviceState.DISCOVER_SETTINGS, device.getState());
104             serialPortEventListener
105                     .serialEvent(new MockSerialPortEvent(mockSerialPort, SerialPortEvent.BI, false, true));
106             assertSame("Expect to be still in discovery state", DeviceState.DISCOVER_SETTINGS, device.getState());
107             serialPortEventListener
108                     .serialEvent(new MockSerialPortEvent(mockSerialPort, SerialPortEvent.DATA_AVAILABLE, false, true));
109             assertSame("Expect to be in normal state", DeviceState.NORMAL, device.getState());
110             device.restart();
111             assertSame("Expect not to start rediscovery when in normal state", DeviceState.NORMAL, device.getState());
112             device.stop();
113         }
114         assertNotNull("Expected to have read a telegram", telegramRef.get());
115     }
116
117     @Test
118     public void testHandleError() throws IOException, PortInUseException {
119         AtomicReference<DSMRConnectorErrorEvent> eventRef = new AtomicReference<>(null);
120         DSMREventListener listener = new DSMREventListener() {
121             @Override
122             public void handleTelegramReceived(P1Telegram telegram) {
123                 fail("No telegram expected:" + telegram);
124             }
125
126             @Override
127             public void handleErrorEvent(DSMRConnectorErrorEvent connectorErrorEvent) {
128                 eventRef.set(connectorErrorEvent);
129             }
130         };
131         try (InputStream inputStream = new ByteArrayInputStream(new byte[] {})) {
132             when(mockSerialPort.getInputStream()).thenReturn(inputStream);
133             // Trigger device to go into error stage with port in use.
134             doAnswer(a -> {
135                 throw new PortInUseException();
136             }).when(mockIdentifier).open(eq(DSMRBindingConstants.DSMR_PORT_NAME), anyInt());
137             DSMRSerialAutoDevice device = new DSMRSerialAutoDevice(serialPortManager, DUMMY_PORTNAME, listener,
138                     new DSMRTelegramListener(), scheduler, 1);
139             device.start();
140             assertSame("Expected an error", DSMRConnectorErrorEvent.IN_USE, eventRef.get());
141             assertSame("Expect to be in error state", DeviceState.ERROR, device.getState());
142             // Trigger device to restart
143             mockValidSerialPort();
144             device.restart();
145             assertSame("Expect to be starting discovery state", DeviceState.DISCOVER_SETTINGS, device.getState());
146             // Trigger device to go into error stage with port doesn't exist.
147             mockIdentifier = null;
148             device = new DSMRSerialAutoDevice(serialPortManager, DUMMY_PORTNAME, listener, new DSMRTelegramListener(),
149                     scheduler, 1);
150             device.start();
151             assertSame("Expected an error", DSMRConnectorErrorEvent.DONT_EXISTS, eventRef.get());
152             assertSame("Expect to be in error state", DeviceState.ERROR, device.getState());
153         }
154     }
155
156     private void mockValidSerialPort() throws PortInUseException {
157         doReturn(mockSerialPort).when(mockIdentifier).open(anyString(), anyInt());
158     }
159
160     /**
161      * Mock class implementing {@link SerialPortEvent}.
162      */
163     private static class MockSerialPortEvent implements SerialPortEvent {
164         private final int eventType;
165         private final boolean newValue;
166
167         public MockSerialPortEvent(SerialPort mockSerialPort, int eventType, boolean oldValue, boolean newValue) {
168             this.eventType = eventType;
169             this.newValue = newValue;
170         }
171
172         @Override
173         public int getEventType() {
174             return eventType;
175         }
176
177         @Override
178         public boolean getNewValue() {
179             return newValue;
180         }
181     }
182 }