]> git.basschouten.com Git - openhab-addons.git/blob
b6be4561e7bc9cddc12c11ca27cd057f669981a3
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.deutschebahn.internal;
14
15 import static org.mockito.ArgumentMatchers.*;
16 import static org.mockito.Mockito.*;
17
18 import java.time.ZoneId;
19 import java.time.ZonedDateTime;
20 import java.util.Arrays;
21 import java.util.Date;
22 import java.util.GregorianCalendar;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.junit.jupiter.api.Test;
26 import org.mockito.Mockito;
27 import org.openhab.binding.deutschebahn.internal.timetable.dto.Event;
28 import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop;
29 import org.openhab.binding.deutschebahn.internal.timetable.dto.TripLabel;
30 import org.openhab.core.config.core.Configuration;
31 import org.openhab.core.library.types.DateTimeType;
32 import org.openhab.core.library.types.StringType;
33 import org.openhab.core.thing.Channel;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingUID;
38 import org.openhab.core.thing.binding.ThingHandlerCallback;
39 import org.openhab.core.thing.internal.BridgeImpl;
40 import org.openhab.core.types.State;
41 import org.openhab.core.types.UnDefType;
42
43 /**
44  * Tests for {@link DeutscheBahnTrainHandler}.
45  * 
46  * @author Sönke Küper - initial contribution.
47  */
48 @NonNullByDefault
49 public class DeutscheBahnTrainHandlerTest {
50
51     private static final String SAMPLE_PATH = "Bielefeld Hbf|Herford|Löhne(Westf)|Bad Oeynhausen|Porta Westfalica|Minden(Westf)|Bückeburg|Stadthagen|Haste|Wunstorf|Hannover Hbf|Lehrte";
52
53     private static Configuration createConfig(int position) {
54         final Configuration config = new Configuration();
55         config.put("position", String.valueOf(position));
56         return config;
57     }
58
59     static Thing mockThing(int id) {
60         final Thing thing = mock(Thing.class);
61         when(thing.getUID()).thenReturn(new ThingUID(DeutscheBahnBindingConstants.TRAIN_TYPE, "train-" + id));
62         when(thing.getThingTypeUID()).thenReturn(DeutscheBahnBindingConstants.TRAIN_TYPE);
63         when(thing.getConfiguration()).thenReturn(createConfig(id));
64         ThingUID bridgeId = new ThingUID(DeutscheBahnBindingConstants.TIMETABLE_TYPE, "timetable");
65         when(thing.getBridgeUID()).thenReturn(bridgeId);
66
67         final Channel tripLabelCategory = mockChannel(thing.getUID(), "trip#category");
68
69         final Channel arrivalPlannedTime = mockChannel(thing.getUID(), "arrival#planned-time");
70         final Channel arrivalLine = mockChannel(thing.getUID(), "arrival#line");
71         final Channel arrivalChangedTime = mockChannel(thing.getUID(), "arrival#changed-time");
72
73         final Channel departurePlannedTime = mockChannel(thing.getUID(), "departure#planned-time");
74         final Channel departurePlannedPlatform = mockChannel(thing.getUID(), "departure#planned-platform");
75         final Channel departureTargetStation = mockChannel(thing.getUID(), "departure#planned-final-station");
76
77         when(thing.getChannelsOfGroup("trip")).thenReturn(Arrays.asList(tripLabelCategory));
78         when(thing.getChannelsOfGroup("arrival"))
79                 .thenReturn(Arrays.asList(arrivalPlannedTime, arrivalLine, arrivalChangedTime));
80         when(thing.getChannelsOfGroup("departure"))
81                 .thenReturn(Arrays.asList(departurePlannedTime, departurePlannedPlatform, departureTargetStation));
82         when(thing.getChannels()).thenReturn(Arrays.asList( //
83                 tripLabelCategory, //
84                 arrivalPlannedTime, arrivalLine, arrivalChangedTime, //
85                 departurePlannedTime, departurePlannedPlatform, departureTargetStation));
86
87         return thing;
88     }
89
90     private static Channel mockChannel(final ThingUID thingId, final String channelId) {
91         final Channel channel = Mockito.mock(Channel.class);
92         when(channel.getUID()).thenReturn(new ChannelUID(thingId, channelId));
93         return channel;
94     }
95
96     private static DeutscheBahnTrainHandler createAndInitHandler(final ThingHandlerCallback callback,
97             final Thing thing) {
98         final DeutscheBahnTrainHandler handler = new DeutscheBahnTrainHandler(thing);
99         handler.setCallback(callback);
100         handler.initialize();
101         return handler;
102     }
103
104     private static State getDateTime(final Date day) {
105         final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(day.toInstant(), ZoneId.systemDefault());
106         return new DateTimeType(zonedDateTime);
107     }
108
109     @Test
110     public void testUpdateChannels() {
111         final Thing thing = mockThing(1);
112         final ThingHandlerCallback callback = mock(ThingHandlerCallback.class);
113         ThingUID bridgeId = new ThingUID(DeutscheBahnBindingConstants.TIMETABLE_TYPE, "timetable");
114         when(callback.getBridge(bridgeId))
115                 .thenReturn(new BridgeImpl(DeutscheBahnBindingConstants.TIMETABLE_TYPE, bridgeId));
116         final DeutscheBahnTrainHandler handler = createAndInitHandler(callback, thing);
117
118         try {
119             verify(callback).statusUpdated(eq(thing), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN)));
120             verify(callback, timeout(1000)).statusUpdated(eq(thing),
121                     argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE)));
122
123             // Provide data that will update the channels
124             TimetableStop stop = new TimetableStop();
125
126             TripLabel label = new TripLabel();
127             label.setC("WFB");
128             stop.setTl(label);
129
130             Event arrival = new Event();
131             arrival.setPt("2108161434");
132             arrival.setL("RE60");
133             stop.setAr(arrival);
134             Event departure = new Event();
135             departure.setPt("2108161435");
136             departure.setPp("2");
137             departure.setPpth(SAMPLE_PATH);
138             stop.setDp(departure);
139
140             handler.updateChannels(stop);
141
142             final Date arrivalTime = new GregorianCalendar(2021, 7, 16, 14, 34).getTime();
143             final Date departureTime = new GregorianCalendar(2021, 7, 16, 14, 35).getTime();
144
145             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "trip#category"),
146                     new StringType("WFB"));
147             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#planned-time"),
148                     getDateTime(arrivalTime));
149             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#line"),
150                     new StringType("RE60"));
151             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#changed-time"),
152                     UnDefType.NULL);
153             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-time"),
154                     getDateTime(departureTime));
155             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-platform"),
156                     new StringType("2"));
157             verify(callback, timeout(1000)).stateUpdated(
158                     new ChannelUID(thing.getUID(), "departure#planned-final-station"), new StringType("Lehrte"));
159         } finally {
160             handler.dispose();
161         }
162     }
163
164     @Test
165     public void testUpdateChannelsWithEventNotPresent() {
166         final Thing thing = mockThing(1);
167         final ThingHandlerCallback callback = mock(ThingHandlerCallback.class);
168         ThingUID bridgeId = new ThingUID(DeutscheBahnBindingConstants.TIMETABLE_TYPE, "timetable");
169         when(callback.getBridge(bridgeId))
170                 .thenReturn(new BridgeImpl(DeutscheBahnBindingConstants.TIMETABLE_TYPE, bridgeId));
171         final DeutscheBahnTrainHandler handler = createAndInitHandler(callback, thing);
172
173         try {
174             verify(callback).statusUpdated(eq(thing), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN)));
175             verify(callback, timeout(1000)).statusUpdated(eq(thing),
176                     argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE)));
177
178             // Provide data that will update the channels
179             TimetableStop stop = new TimetableStop();
180
181             Event arrival = new Event();
182             arrival.setPt("2108161434");
183             arrival.setL("RE60");
184             stop.setAr(arrival);
185
186             handler.updateChannels(stop);
187
188             final Date arrivalTime = new GregorianCalendar(2021, 7, 16, 14, 34).getTime();
189
190             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "trip#category"),
191                     UnDefType.UNDEF);
192
193             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#planned-time"),
194                     getDateTime(arrivalTime));
195             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#line"),
196                     new StringType("RE60"));
197             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#changed-time"),
198                     UnDefType.NULL);
199
200             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-time"),
201                     UnDefType.UNDEF);
202             verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-platform"),
203                     UnDefType.UNDEF);
204             verify(callback, timeout(1000))
205                     .stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-final-station"), UnDefType.UNDEF);
206         } finally {
207             handler.dispose();
208         }
209     }
210
211     @Test
212     public void testWithoutBridgeStateUpdatesToOffline() {
213         final Thing thing = mockThing(1);
214         final ThingHandlerCallback callback = mock(ThingHandlerCallback.class);
215         final DeutscheBahnTrainHandler handler = createAndInitHandler(callback, thing);
216
217         try {
218             verify(callback).statusUpdated(eq(thing), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN)));
219             verify(callback, timeout(1000)).statusUpdated(eq(thing),
220                     argThat(arg -> arg.getStatus().equals(ThingStatus.OFFLINE)));
221         } finally {
222             handler.dispose();
223         }
224     }
225 }