2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.deutschebahn.internal.timetable;
15 import static org.hamcrest.MatcherAssert.assertThat;
16 import static org.hamcrest.Matchers.*;
17 import static org.junit.jupiter.api.Assertions.assertEquals;
19 import java.util.Calendar;
20 import java.util.GregorianCalendar;
21 import java.util.List;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.junit.jupiter.api.Test;
25 import org.openhab.binding.deutschebahn.internal.EventType;
26 import org.openhab.binding.deutschebahn.internal.TimetableStopFilter;
27 import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop;
30 * Tests for the {@link TimetableLoader}.
32 * @author Sönke Küper - initial contribution
35 public class TimetableLoaderTest implements TimetablesV1ImplTestHelper {
38 public void testLoadRequiredStopCount() throws Exception {
39 final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata();
40 final TimeproviderStub timeProvider = new TimeproviderStub();
41 final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.ALL,
42 EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 20);
44 timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 30);
46 final List<TimetableStop> stops = loader.getTimetableStops();
47 assertThat(timeTableTestModule.getRequestedPlanUrls(),
48 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09",
49 "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/10",
50 "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/11"));
51 assertThat(timeTableTestModule.getRequestedFullChangesUrls(),
52 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226"));
53 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty());
55 assertThat(stops, hasSize(21));
56 assertEquals("-5296516961807204721-2108160906-5", stops.get(0).getId());
57 assertEquals("-3222259045572671319-2108161155-1", stops.get(20).getId());
59 // when requesting again no further call to plan is made, because required stops are available.
60 final List<TimetableStop> stops02 = loader.getTimetableStops();
61 assertThat(stops02, hasSize(21));
62 assertThat(timeTableTestModule.getRequestedPlanUrls(), hasSize(3));
63 assertThat(timeTableTestModule.getRequestedFullChangesUrls(), hasSize(1));
64 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty());
68 public void testLoadNewDataIfRequired() throws Exception {
69 final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata();
70 final TimeproviderStub timeProvider = new TimeproviderStub();
71 final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.ALL,
72 EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 8);
74 timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 0);
76 final List<TimetableStop> stops = loader.getTimetableStops();
77 assertThat(timeTableTestModule.getRequestedPlanUrls(),
78 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09"));
79 assertThat(timeTableTestModule.getRequestedFullChangesUrls(),
80 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226"));
81 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty());
83 assertThat(stops, hasSize(8));
84 assertEquals("1763676552526687479-2108160847-6", stops.get(0).getId());
85 assertEquals("8681599812964340829-2108160955-1", stops.get(7).getId());
87 // Move clock ahead for 30 minutes, so that some of the fetched data is in past and new plan data must be
89 timeProvider.moveAhead(30 * 60);
91 final List<TimetableStop> stops02 = loader.getTimetableStops();
92 assertThat(stops02, hasSize(13));
93 assertThat(timeTableTestModule.getRequestedPlanUrls(),
94 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09",
95 "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/10"));
96 assertThat(timeTableTestModule.getRequestedFullChangesUrls(),
97 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226",
98 "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226"));
99 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty());
101 assertEquals("-5296516961807204721-2108160906-5", stops02.get(0).getId());
102 assertEquals("-3376513334056532423-2108161055-1", stops02.get(12).getId());
106 public void testRequestUpdates() throws Exception {
107 final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata();
108 final TimeproviderStub timeProvider = new TimeproviderStub();
109 final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.ALL,
110 EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 1);
112 timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 30);
114 // First call - plan and full changes are requested.
115 loader.getTimetableStops();
116 assertThat(timeTableTestModule.getRequestedPlanUrls(),
117 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09"));
118 assertThat(timeTableTestModule.getRequestedFullChangesUrls(),
119 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226"));
120 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty());
122 // Changes are updated only every 30 seconds, so move clock ahead 20 seconds, no request is made
123 timeProvider.moveAhead(20);
124 loader.getTimetableStops();
126 assertThat(timeTableTestModule.getRequestedPlanUrls(),
127 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09"));
128 assertThat(timeTableTestModule.getRequestedFullChangesUrls(),
129 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226"));
130 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty());
132 // Move ahead 10 seconds, so recent changes are fetched
133 timeProvider.moveAhead(10);
134 loader.getTimetableStops();
135 assertThat(timeTableTestModule.getRequestedPlanUrls(),
136 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09"));
137 assertThat(timeTableTestModule.getRequestedFullChangesUrls(),
138 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226"));
139 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(),
140 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/rchg/8000226"));
142 // Move again ahead 30 seconds, recent changes are fetched again
143 timeProvider.moveAhead(30);
144 loader.getTimetableStops();
145 assertThat(timeTableTestModule.getRequestedPlanUrls(),
146 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09"));
147 assertThat(timeTableTestModule.getRequestedFullChangesUrls(),
148 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226"));
149 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(),
150 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/rchg/8000226",
151 "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/rchg/8000226"));
153 // If recent change were not updated last 120 seconds the full changes must be requested
154 timeProvider.moveAhead(120);
155 loader.getTimetableStops();
156 assertThat(timeTableTestModule.getRequestedPlanUrls(),
157 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09"));
158 assertThat(timeTableTestModule.getRequestedFullChangesUrls(),
159 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226",
160 "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226"));
161 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(),
162 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/rchg/8000226",
163 "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/rchg/8000226"));
167 public void testReturnOnlyArrivals() throws Exception {
168 final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata();
169 final TimeproviderStub timeProvider = new TimeproviderStub();
170 final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.ARRIVALS,
171 EventType.ARRIVAL, timeProvider, EVA_LEHRTE, 20);
173 // Simulate that only one url is available
174 timeTableTestModule.addAvailableUrl(
175 "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09");
177 timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 0);
179 final List<TimetableStop> stops = loader.getTimetableStops();
181 // File contains 8 stops, but 2 are only departures
182 assertThat(stops, hasSize(6));
183 assertEquals("1763676552526687479-2108160847-6", stops.get(0).getId());
184 assertEquals("-735649762452915464-2108160912-6", stops.get(5).getId());
188 public void testReturnOnlyDepartures() throws Exception {
189 final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata();
190 final TimeproviderStub timeProvider = new TimeproviderStub();
191 final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.DEPARTURES,
192 EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 20);
194 // Simulate that only one url is available
195 timeTableTestModule.addAvailableUrl(
196 "https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09");
198 timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 0);
200 final List<TimetableStop> stops = loader.getTimetableStops();
202 // File contains 8 stops, but 2 are only arrivals
203 assertThat(stops, hasSize(6));
204 assertEquals("-94442819435724762-2108160916-1", stops.get(0).getId());
205 assertEquals("8681599812964340829-2108160955-1", stops.get(5).getId());
209 public void testRemoveEntryOnlyIfChangedTimeIsInPast() throws Exception {
210 final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata();
211 final TimeproviderStub timeProvider = new TimeproviderStub();
212 final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.DEPARTURES,
213 EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 1);
215 timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 35);
217 final List<TimetableStop> stops = loader.getTimetableStops();
218 assertThat(timeTableTestModule.getRequestedPlanUrls(),
219 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/8000226/210816/09"));
220 assertThat(timeTableTestModule.getRequestedFullChangesUrls(),
221 contains("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8000226"));
222 assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty());
224 // Stop -5296516961807204721-2108160906-5 has its planned time at 9:34, but its included because its changed
226 assertThat(stops, hasSize(4));
227 assertEquals("-5296516961807204721-2108160906-5", stops.get(0).getId());
228 assertEquals("2108160942", stops.get(0).getDp().getCt());
229 assertEquals("8681599812964340829-2108160955-1", stops.get(3).getId());