View Javadoc
1   package de.dlr.shepard.data.timeseries.utilities;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertThrows;
5   import static org.junit.jupiter.api.Assertions.assertTrue;
6   
7   import de.dlr.shepard.common.exceptions.InvalidBodyException;
8   import de.dlr.shepard.data.timeseries.TimeseriesTestDataGenerator;
9   import de.dlr.shepard.data.timeseries.io.TimeseriesWithDataPoints;
10  import de.dlr.shepard.data.timeseries.model.Timeseries;
11  import de.dlr.shepard.data.timeseries.model.TimeseriesDataPoint;
12  import de.dlr.shepard.data.timeseries.model.enums.CsvFormat;
13  import de.dlr.shepard.data.timeseries.services.TimeseriesCsvService;
14  import jakarta.inject.Inject;
15  import java.io.ByteArrayInputStream;
16  import java.io.IOException;
17  import java.io.InputStream;
18  import java.nio.charset.StandardCharsets;
19  import java.util.ArrayList;
20  import java.util.List;
21  import org.apache.commons.io.IOUtils;
22  import org.junit.jupiter.api.Test;
23  
24  public class CsvConverterTest {
25  
26    @Inject
27    TimeseriesCsvService timeseriesService;
28  
29    @Test
30    void testConvertToCsv_multipleTypes_success() throws IOException {
31      var timeseries = TimeseriesTestDataGenerator.generateTimeseries("temperature");
32      List<TimeseriesDataPoint> dataPoints = new ArrayList<>(
33        List.of(
34          new TimeseriesDataPoint(88551122, 22.1),
35          new TimeseriesDataPoint(88551123, 4),
36          new TimeseriesDataPoint(88551124, 22.2),
37          new TimeseriesDataPoint(88551125, true),
38          new TimeseriesDataPoint(88551126, "Hello World")
39        )
40      );
41  
42      String expectedCsvString =
43        """
44        DEVICE,FIELD,LOCATION,MEASUREMENT,SYMBOLICNAME,TIMESTAMP,VALUE
45        device,field,location,temperature,symbolicName,88551122,22.1
46        device,field,location,temperature,symbolicName,88551123,4
47        device,field,location,temperature,symbolicName,88551124,22.2
48        device,field,location,temperature,symbolicName,88551125,true
49        device,field,location,temperature,symbolicName,88551126,Hello World
50        """;
51  
52      String actualCsvString = IOUtils.toString(
53        CsvConverter.convertToCsv(timeseries, dataPoints, CsvFormat.ROW),
54        StandardCharsets.UTF_8
55      );
56  
57      assertEquals(expectedCsvString, actualCsvString);
58    }
59  
60    @Test
61    void testConvertToCsv_emptyData_success() throws IOException {
62      var timeseries = TimeseriesTestDataGenerator.generateTimeseries("temperature");
63      List<TimeseriesDataPoint> dataPoints = new ArrayList<>();
64  
65      String expectedCsvString = "";
66  
67      String actualCsvString = IOUtils.toString(
68        CsvConverter.convertToCsv(timeseries, dataPoints, CsvFormat.ROW),
69        StandardCharsets.UTF_8
70      );
71  
72      assertEquals(expectedCsvString, actualCsvString);
73    }
74  
75    @Test
76    void testConvertToTimeseriesWithData_multipleTypes_success() throws IOException {
77      String actualCsvString =
78        """
79        DEVICE,FIELD,LOCATION,MEASUREMENT,SYMBOLICNAME,TIMESTAMP,VALUE
80        device,field,location,double,symbolicName,88551122,22.1
81        device,field,location,integer,symbolicName,88551123,4
82        device,field,location,double,symbolicName,88551124,22.2
83        device,field,location,boolean,symbolicName,88551125,true
84        device,field,location,integer,symbolicName,88551126,5
85        device,field,location,string,symbolicName,88551127,Hello World
86        device,field,location,boolean,symbolicName,88551128,false
87        """;
88  
89      var expectedTimeseriesDouble = new Timeseries("double", "device", "location", "symbolicName", "field");
90      var expectedTimeseriesInteger = new Timeseries("integer", "device", "location", "symbolicName", "field");
91      var expectedTimeseriesBoolean = new Timeseries("boolean", "device", "location", "symbolicName", "field");
92      var expectedTimeseriesString = new Timeseries("string", "device", "location", "symbolicName", "field");
93  
94      List<TimeseriesDataPoint> expectedDataPointsIODouble = new ArrayList<>(
95        List.of(new TimeseriesDataPoint(88551122, 22.1), new TimeseriesDataPoint(88551124, 22.2))
96      );
97  
98      List<TimeseriesDataPoint> expectedDataPointsIOInteger = new ArrayList<>(
99        List.of(new TimeseriesDataPoint(88551123, 4), new TimeseriesDataPoint(88551126, 5))
100     );
101 
102     List<TimeseriesDataPoint> expectedDataPointsIOBoolean = new ArrayList<>(
103       List.of(new TimeseriesDataPoint(88551125, true), new TimeseriesDataPoint(88551128, false))
104     );
105 
106     List<TimeseriesDataPoint> expectedDataPointsIOString = new ArrayList<>(
107       List.of(new TimeseriesDataPoint(88551127, "Hello World"))
108     );
109 
110     InputStream timeseriesDataStream = new ByteArrayInputStream(actualCsvString.getBytes(StandardCharsets.UTF_8));
111 
112     List<TimeseriesWithDataPoints> actualTimeseriesWithDataPointsList = CsvConverter.convertToTimeseriesWithData(
113       timeseriesDataStream
114     );
115     List<TimeseriesWithDataPoints> expectedTimeseriesWithDataPointsList = List.of(
116       new TimeseriesWithDataPoints(expectedTimeseriesBoolean, expectedDataPointsIOBoolean),
117       new TimeseriesWithDataPoints(expectedTimeseriesInteger, expectedDataPointsIOInteger),
118       new TimeseriesWithDataPoints(expectedTimeseriesString, expectedDataPointsIOString),
119       new TimeseriesWithDataPoints(expectedTimeseriesDouble, expectedDataPointsIODouble)
120     );
121 
122     assertEquals(4, actualTimeseriesWithDataPointsList.size());
123     assertTrue(actualTimeseriesWithDataPointsList.containsAll(expectedTimeseriesWithDataPointsList));
124     assertTrue(expectedTimeseriesWithDataPointsList.containsAll(actualTimeseriesWithDataPointsList));
125   }
126 
127   @Test
128   void testConvertToTimeseriesWithData_emptyData() throws IOException {
129     String actualCsvString = "DEVICE,FIELD,LOCATION,MEASUREMENT,SYMBOLICNAME,TIMESTAMP,VALUE";
130     InputStream timeseriesDataStream = new ByteArrayInputStream(actualCsvString.getBytes(StandardCharsets.UTF_8));
131     var actualTimeseriesDataIOMap = CsvConverter.convertToTimeseriesWithData(timeseriesDataStream);
132     assertEquals(0, actualTimeseriesDataIOMap.size());
133   }
134 
135   @Test
136   void testConvertToTimeseriesWithData_csvFormatError_failure() throws IOException {
137     String wrongFormatCSV =
138       """
139       DEVICE,FIELD,LOCATION,MEASUREMENT,SYMBOLICNAME,TIMESTAMP,VALUE
140       device,field,location,double,symbolicName,88551122,22.1,,
141       device,field,location,integer,symbolicName,88551123,4
142       device,field,location,boolean,symbolicName,88551128,false
143       """;
144 
145     InputStream timeseriesDataStream = new ByteArrayInputStream(wrongFormatCSV.getBytes(StandardCharsets.UTF_8));
146 
147     // this RuntimeException is a InvalidBodyException wrapped into a runtime exception
148     RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
149       CsvConverter.convertToTimeseriesWithData(timeseriesDataStream);
150     });
151 
152     Throwable cause = thrown.getCause();
153     assertEquals(InvalidBodyException.class, cause.getClass());
154     assertEquals("Number of data fields does not match number of headers.", cause.getMessage());
155   }
156 }