1 package de.dlr.shepard.data.timeseries.services;
2
3 import static org.junit.jupiter.api.Assertions.assertEquals;
4 import static org.junit.jupiter.api.Assertions.assertTrue;
5 import static org.mockito.Mockito.when;
6
7 import de.dlr.shepard.auth.security.AuthenticationContext;
8 import de.dlr.shepard.auth.users.entities.User;
9 import de.dlr.shepard.auth.users.services.UserService;
10 import de.dlr.shepard.data.timeseries.TimeseriesTestDataGenerator;
11 import de.dlr.shepard.data.timeseries.io.TimeseriesContainerIO;
12 import de.dlr.shepard.data.timeseries.io.TimeseriesWithDataPoints;
13 import de.dlr.shepard.data.timeseries.model.Timeseries;
14 import de.dlr.shepard.data.timeseries.model.TimeseriesDataPoint;
15 import de.dlr.shepard.data.timeseries.model.TimeseriesDataPointsQueryParams;
16 import de.dlr.shepard.data.timeseries.model.TimeseriesEntity;
17 import de.dlr.shepard.data.timeseries.utilities.CsvConverter;
18 import io.quarkus.test.InjectMock;
19 import io.quarkus.test.junit.QuarkusTest;
20 import jakarta.inject.Inject;
21 import jakarta.transaction.Transactional;
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.InputStreamReader;
26 import java.net.URISyntaxException;
27 import java.nio.file.Files;
28 import java.util.ArrayList;
29 import java.util.List;
30 import org.junit.jupiter.api.Test;
31
32 @QuarkusTest
33 public class TimeseriesCsvServiceTest {
34
35 @InjectMock
36 UserService userService;
37
38 @InjectMock
39 AuthenticationContext authenticationContext;
40
41 @Inject
42 TimeseriesContainerService timeseriesContainerService;
43
44 @Inject
45 TimeseriesService timeseriesService;
46
47 @Inject
48 TimeseriesCsvService timeseriesCsvService;
49
50 private final String containerName = "AnotherContainer";
51
52
53
54
55
56 @Test
57 @Transactional
58 public void exportTimeseriesDataToCsv_oneTimeseriesWithDoubleValues_success() throws IOException, URISyntaxException {
59 User user = new User("Testuser");
60 TimeseriesContainerIO containerIO = new TimeseriesContainerIO();
61 containerIO.setName(containerName);
62
63 when(userService.getCurrentUser()).thenReturn(user);
64 when(authenticationContext.getCurrentUserName()).thenReturn(user.getUsername());
65
66 var container = timeseriesContainerService.createContainer(containerIO);
67 var timeseries = TimeseriesTestDataGenerator.generateTimeseries("water_level");
68 InstantHelper instantHelper = InstantHelper.fromGermanDate("01.01.2024");
69 List<TimeseriesDataPoint> dataPoints = new ArrayList<>(
70 List.of(
71 TimeseriesTestDataGenerator.generateDataPointDouble(instantHelper.toNano(), 90.0),
72 TimeseriesTestDataGenerator.generateDataPointDouble(instantHelper.addSeconds(1).toNano(), 120.57),
73 TimeseriesTestDataGenerator.generateDataPointDouble(instantHelper.addSeconds(2).toNano(), 127.25),
74 TimeseriesTestDataGenerator.generateDataPointDouble(instantHelper.addSeconds(3).toNano(), 129.25),
75 TimeseriesTestDataGenerator.generateDataPointDouble(instantHelper.addSeconds(4).toNano(), 134.0)
76 )
77 );
78
79 this.timeseriesService.saveDataPoints(container.getId(), timeseries, dataPoints);
80 TimeseriesDataPointsQueryParams queryParams = new TimeseriesDataPointsQueryParams(
81 InstantHelper.fromGermanDate("01.01.2024").toNano(),
82 instantHelper.toNano(),
83 null,
84 null,
85 null
86 );
87 var actual = this.timeseriesCsvService.exportTimeseriesDataToCsv(container.getId(), timeseries, queryParams);
88
89 StringBuilder actualCsvContent = new StringBuilder();
90 try (BufferedReader reader = new BufferedReader(new InputStreamReader(actual))) {
91 String line;
92 while ((line = reader.readLine()) != null) {
93 actualCsvContent.append(line).append("\n");
94 }
95 }
96
97 var expectedCsvFile = new File(
98 getClass().getClassLoader().getResource("timeseries_export_experimental_double.csv").toURI()
99 );
100 var expectedCsvContent = Files.readString(expectedCsvFile.toPath());
101
102 assertEquals(actualCsvContent.toString().trim(), expectedCsvContent.trim());
103 }
104
105 @Test
106 @Transactional
107 public void exportTimeseriesDataToCsv_oneTimeseriesWithStringValues_success() throws IOException, URISyntaxException {
108 User user = new User("Testuser");
109 TimeseriesContainerIO containerIO = new TimeseriesContainerIO();
110 containerIO.setName(containerName);
111
112 when(userService.getCurrentUser()).thenReturn(user);
113 when(authenticationContext.getCurrentUserName()).thenReturn(user.getUsername());
114
115 var container = timeseriesContainerService.createContainer(containerIO);
116 var timeseries = TimeseriesTestDataGenerator.generateTimeseries("status");
117 InstantHelper instantHelper = InstantHelper.fromGermanDate("01.01.2024");
118 List<TimeseriesDataPoint> dataPoints = new ArrayList<>(
119 List.of(TimeseriesTestDataGenerator.generateDataPointString(instantHelper.toNano(), "running"))
120 );
121
122 this.timeseriesService.saveDataPoints(container.getId(), timeseries, dataPoints);
123 TimeseriesDataPointsQueryParams queryParams = new TimeseriesDataPointsQueryParams(
124 instantHelper.toNano(),
125 instantHelper.addSeconds(2).toNano(),
126 null,
127 null,
128 null
129 );
130 var actual = this.timeseriesCsvService.exportTimeseriesDataToCsv(container.getId(), timeseries, queryParams);
131
132 StringBuilder actualCsvContent = new StringBuilder();
133 try (BufferedReader reader = new BufferedReader(new InputStreamReader(actual))) {
134 String line;
135 while ((line = reader.readLine()) != null) {
136 actualCsvContent.append(line).append("\n");
137 }
138 }
139
140 var expectedCsvFile = new File(
141 getClass().getClassLoader().getResource("timeseries_export_experimental_string.csv").toURI()
142 );
143 var expectedCsvContent = Files.readString(expectedCsvFile.toPath());
144
145 assertEquals(actualCsvContent.toString().trim(), expectedCsvContent.trim());
146 }
147
148 @Test
149 @Transactional
150 public void exportTimeseriesDataToCsv_oneTimeseriesWithBooleanValues_success()
151 throws IOException, URISyntaxException {
152 User user = new User("Testuser");
153 TimeseriesContainerIO containerIO = new TimeseriesContainerIO();
154 containerIO.setName(containerName);
155
156 when(userService.getCurrentUser()).thenReturn(user);
157 when(authenticationContext.getCurrentUserName()).thenReturn(user.getUsername());
158
159 var container = timeseriesContainerService.createContainer(containerIO);
160 var timeseries = TimeseriesTestDataGenerator.generateTimeseries("motion");
161 InstantHelper instantHelper = InstantHelper.fromGermanDate("01.01.2024");
162 List<TimeseriesDataPoint> dataPoints = new ArrayList<>(
163 List.of(
164 TimeseriesTestDataGenerator.generateDataPointBoolean(instantHelper.toNano(), true),
165 TimeseriesTestDataGenerator.generateDataPointBoolean(instantHelper.addSeconds(1).toNano(), false),
166 TimeseriesTestDataGenerator.generateDataPointBoolean(instantHelper.addSeconds(2).toNano(), true),
167 TimeseriesTestDataGenerator.generateDataPointBoolean(instantHelper.addSeconds(3).toNano(), false),
168 TimeseriesTestDataGenerator.generateDataPointBoolean(instantHelper.addSeconds(4).toNano(), true)
169 )
170 );
171
172 this.timeseriesService.saveDataPoints(container.getId(), timeseries, dataPoints);
173 TimeseriesDataPointsQueryParams queryParams = new TimeseriesDataPointsQueryParams(
174 InstantHelper.fromGermanDate("01.01.2024").toNano(),
175 instantHelper.toNano(),
176 null,
177 null,
178 null
179 );
180 var actual = this.timeseriesCsvService.exportTimeseriesDataToCsv(container.getId(), timeseries, queryParams);
181
182 StringBuilder actualCsvContent = new StringBuilder();
183 try (BufferedReader reader = new BufferedReader(new InputStreamReader(actual))) {
184 String line;
185 while ((line = reader.readLine()) != null) {
186 actualCsvContent.append(line).append("\n");
187 }
188 }
189
190 var expectedCsvFile = new File(
191 getClass().getClassLoader().getResource("timeseries_export_experimental_boolean.csv").toURI()
192 );
193 var expectedCsvContent = Files.readString(expectedCsvFile.toPath());
194
195 assertEquals(actualCsvContent.toString().trim(), expectedCsvContent.trim());
196 }
197
198
199
200
201
202 @Test
203 @Transactional
204 public void importTimeseriesFromCsv_multipleTimeseriesWithMultipleValues_success()
205 throws IOException, URISyntaxException {
206 User user = new User("Testuser");
207 TimeseriesContainerIO containerIO = new TimeseriesContainerIO();
208 containerIO.setName(containerName);
209
210 when(userService.getCurrentUser()).thenReturn(user);
211 when(authenticationContext.getCurrentUserName()).thenReturn(user.getUsername());
212
213 var container = timeseriesContainerService.createContainer(containerIO);
214
215 File importCSVFile = new File(
216 getClass().getClassLoader().getResource("timeseries_import_experimental.csv").toURI()
217 );
218
219 String csvFileContent = Files.readString(importCSVFile.toPath());
220
221 timeseriesCsvService.importTimeseriesFromCsv(container.getId(), importCSVFile.toPath().toString());
222
223 List<TimeseriesEntity> availTimeseriesList = timeseriesService.getTimeseriesAvailable(container.getId());
224
225 List<Timeseries> expTimeseries = new ArrayList<Timeseries>();
226
227 for (var currTimeseries : availTimeseriesList) {
228 expTimeseries.add(
229 new Timeseries(
230 currTimeseries.getMeasurement(),
231 currTimeseries.getDevice(),
232 currTimeseries.getLocation(),
233 currTimeseries.getSymbolicName(),
234 currTimeseries.getField()
235 )
236 );
237 }
238
239 var actualTimeseriesDataMap = new ArrayList<TimeseriesWithDataPoints>();
240 expTimeseries
241 .stream()
242 .forEach(timeseries -> {
243 actualTimeseriesDataMap.add(
244 new TimeseriesWithDataPoints(
245 timeseries,
246 timeseriesService.getDataPointsByTimeseries(
247 container.getId(),
248 timeseries,
249 new TimeseriesDataPointsQueryParams(
250 InstantHelper.fromGermanDate("01.01.2024").addHours(-1).toNano(),
251 InstantHelper.fromGermanDate("01.01.2024").addHours(1).toNano(),
252 null,
253 null,
254 null
255 )
256 )
257 )
258 );
259 });
260
261 var actualTimeSeriesStream = CsvConverter.convertToCsv(actualTimeseriesDataMap);
262
263 int lineCounter = 0;
264
265 try (BufferedReader reader = new BufferedReader(new InputStreamReader(actualTimeSeriesStream))) {
266 String line;
267 while ((line = reader.readLine()) != null) {
268 lineCounter += 1;
269 assertTrue(
270 csvFileContent.contains(line),
271 String.format("Line '%s' is not contained in original CSV file", line)
272 );
273 }
274 }
275
276 assertEquals(csvFileContent.split("\n").length, lineCounter);
277 }
278
279 @Test
280 @Transactional
281 public void importTimeseriesFromCsv_emptyTimeseries_noDataCreation() throws IOException, URISyntaxException {
282 User user = new User("Testuser");
283 TimeseriesContainerIO containerIO = new TimeseriesContainerIO();
284 containerIO.setName(containerName);
285
286 when(userService.getCurrentUser()).thenReturn(user);
287 when(authenticationContext.getCurrentUserName()).thenReturn(user.getUsername());
288
289 var container = timeseriesContainerService.createContainer(containerIO);
290
291 File importCSVFile = new File(
292 getClass().getClassLoader().getResource("timeseries_import_experimental_empty.csv").toURI()
293 );
294
295 timeseriesCsvService.importTimeseriesFromCsv(container.getId(), importCSVFile.toPath().toString());
296
297 List<TimeseriesEntity> availTimeseriesList = timeseriesService.getTimeseriesAvailable(container.getId());
298
299 assertEquals(
300 0,
301 availTimeseriesList.size(),
302 "Imported empty timeseries payload, but a timeseries was created from this empty payload."
303 );
304 }
305 }