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