View Javadoc
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     * exportTimeseriesDataToCsv
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    * importTimeseriesFromCsv
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     // make sure the number of lines in both CSV files are equal
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 }