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