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
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 }