ifw-daq  3.0.0-pre2
IFW Data Acquisition modules
testDpSpec.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @ingroup daq_dpm_libmerge
4  * @copyright ESO - European Southern Observatory
5  */
6 #include <daq/error/report.hpp>
7 #include <daq/json/dpSpec.hpp>
8 
9 #include <gmock/gmock.h>
10 #include <gtest/gtest.h>
11 
12 #include <daq/test/expect.hpp>
13 
14 using namespace testing;
15 
16 namespace daq::json {
17 
18 class TestParseLocation : public ::testing::Test {};
19 
20 TEST_F(TestParseLocation, ParseSucceeds) {
21  {
22  Location o = ParseSourceLocation("user@foo");
23  EXPECT_EQ(o.host, "");
24  EXPECT_EQ(o.path, "foo");
25  }
26  {
27  Location o = ParseSourceLocation("foo");
28  EXPECT_EQ(o.host, "");
29  EXPECT_EQ(o.path, "foo");
30  }
31  {
32  Location o = ParseSourceLocation("host:~/files/file.fits");
33  EXPECT_EQ(o.host, "host");
34  EXPECT_EQ(o.path, "~/files/file.fits");
35  }
36  {
37  Location o = ParseSourceLocation("host:/path/to/file:with:colons.fits");
38  EXPECT_EQ(o.host, "host");
39  EXPECT_EQ(o.path, "/path/to/file:with:colons.fits");
40  }
41  {
42  Location o = ParseSourceLocation("user@host:/path/to/file:with:colons.fits");
43  EXPECT_EQ(o.host, "host");
44  EXPECT_EQ(o.path, "/path/to/file:with:colons.fits");
45  }
46 }
47 
48 TEST_F(TestParseLocation, ParseFails) {
49  EXPECT_THROW(ParseSourceLocation("user@"), std::invalid_argument);
50  EXPECT_THROW(ParseSourceLocation("@"), std::invalid_argument);
51  EXPECT_THROW(ParseSourceLocation(":"), std::invalid_argument);
52  EXPECT_THROW(ParseSourceLocation("user@:"), std::invalid_argument);
53 }
54 
55 class TestParseDpSpec : public ::testing::Test {
56 public:
57  void SetUp() {
58  using namespace nlohmann;
59  m_spec = R"(
60  {
61  "id": "TEST.ID",
62  "target": {
63  "fileId": "TEST.FILEID",
64  "source": {
65  "sourceName": "dcs",
66  "location": "dcs-host:/path/to/somefile.fits",
67  "keywordRules": [
68  {
69  "type": "transform",
70  "selectionPatterns": [
71  "+e INS *"
72  ],
73  "regex": "^INS ",
74  "format": "INS2 "
75  },
76  {
77  "type": "filter",
78  "selectionPatterns": [
79  "+e INS2 *",
80  "+v VALUEKW"
81  ]
82  }
83  ]
84  }
85  },
86  "sources": [
87  {
88  "type": "fitsKeywords",
89  "sourceName": "ocm",
90  "keywordRules": [
91  {
92  "type": "filter",
93  "selectionPatterns": [
94  "+e *",
95  "+v *"
96  ]
97  }
98  ],
99  "keywords": [
100  {
101  "type": "valueKeyword",
102  "name": "ORIGIN",
103  "value": "ESO-PARANAL"
104  },
105  {
106  "type": "valueKeyword",
107  "name": "TELESCOP",
108  "value": "ESO-ELT"
109  },
110  {
111  "type": "valueKeyword",
112  "name": "OBJECT",
113  "value": "OBJECT,SKY"
114  },
115  {
116  "type": "esoKeyword",
117  "name": "OCS TEMPL ID",
118  "value": "template-id"
119  },
120  {
121  "type": "literalKeyword",
122  "value": "COMMENT Example of a commentary keyword."
123  }
124  ]
125  },
126  {
127  "type": "fitsKeywords",
128  "sourceName": "tcs",
129  "keywordRules": [
130  ],
131  "keywords": [
132  {
133  "type": "esoKeyword",
134  "name": "TEL AIRM START",
135  "value": 1.072
136  },
137  {
138  "type": "esoKeyword",
139  "name": "TEL AIRM END",
140  "value": 1.08
141  }
142  ]
143  },
144  {
145  "type": "fitsFile",
146  "sourceName": "fcs",
147  "location": "fcs-host:/path/to/somefile.fits",
148  "keywordRules": [
149  {
150  "type": "filter",
151  "selectionPatterns": [
152  "+e INS *",
153  "-e INS TEMP[12] *",
154  "+v VALUEKW"
155  ]
156  },
157  {
158  "type": "transform",
159  "selectionPatterns": [
160  "+e INS *"
161  ],
162  "regex": "^INS ",
163  "format": "INS2 "
164  }
165  ]
166  }
167  ]
168  }
169  )"_json;
170  }
171 
172  nlohmann::json m_spec;
173 };
174 
175 TEST_F(TestParseDpSpec, ParseSucceeds) {
176  DpSpec spec = ParseDpSpec(m_spec);
177  EXPECT_EQ(spec.id, "TEST.ID");
178  EXPECT_EQ(spec.target.file_id, "TEST.FILEID");
179 
180  ASSERT_TRUE(spec.target.source.has_value());
181  EXPECT_EQ(spec.target.source->source_name, "dcs");
182 
183  ASSERT_EQ(spec.target.source->keyword_rules.size(), 2u);
184  auto const& transform = std::get<KeywordTransform>(spec.target.source->keyword_rules.at(0));
185  ASSERT_EQ(transform.selection_patterns.size(), 1);
186  EXPECT_EQ(transform.selection_patterns[0], "+e INS *");
187  EXPECT_EQ(transform.format, "INS2 ");
188  auto const& filter = std::get<KeywordFilter>(spec.target.source->keyword_rules.at(1));
189  EXPECT_THAT(filter.selection_patterns, ElementsAre("+e INS2 *", "+v VALUEKW"));
190 
191  ASSERT_EQ(3u, spec.sources.size());
192  auto const& ocm_kws_var = spec.sources[0];
193  ASSERT_TRUE(std::holds_alternative<FitsKeywordsSource>(ocm_kws_var));
194  auto const& tcs_kws_var = spec.sources[1];
195  ASSERT_TRUE(std::holds_alternative<FitsKeywordsSource>(tcs_kws_var));
196  auto const& fcs_fits_var = spec.sources[2];
197  ASSERT_TRUE(std::holds_alternative<FitsFileSource>(fcs_fits_var));
198  auto const& ocm_kws = std::get<FitsKeywordsSource>(spec.sources[0]);
199  auto const& tcs_kws = std::get<FitsKeywordsSource>(spec.sources[1]);
200  auto const& fcs_fits = std::get<FitsFileSource>(spec.sources[2]);
201 
202  {
203  EXPECT_EQ(ocm_kws.source_name, "ocm");
204  ASSERT_EQ(ocm_kws.keyword_rules.size(), 1);
205  auto const& filter = std::get<KeywordFilter>(ocm_kws.keyword_rules.at(0));
206  ASSERT_EQ(filter.selection_patterns.size(), 2);
207  EXPECT_THAT(filter.selection_patterns, ElementsAre("+e *", "+v *"));
208  }
209 
210  EXPECT_EQ(tcs_kws.source_name, "tcs");
211  EXPECT_EQ(fcs_fits.source_name, "fcs");
212 }
213 
214 TEST_F(TestParseDpSpec, ParseSucceedsWithOptionalTarget) {
215  m_spec["target"].erase("targetSource");
216  EXPECT_NO_THROW(ParseDpSpec(m_spec));
217 }
218 
219 TEST_F(TestParseDpSpec, ParseSucceedsWithOptionalSources) {
220  m_spec.erase("sources");
221  EXPECT_NO_THROW(ParseDpSpec(m_spec));
222 }
223 
224 TEST_F(TestParseDpSpec, ParseSucceedsWithOptionalSourcesEmpty) {
225  m_spec["sources"] = nlohmann::json::array();
226  EXPECT_NO_THROW(ParseDpSpec(m_spec));
227 }
228 
229 TEST_F(TestParseDpSpec, ParseFailsWithMissingId) {
230  m_spec.erase("id");
232  ParseDpSpec(m_spec), DpSpecError, MatchesRegex(R"(.*\‍(/id\).*missing.*)"));
233 }
234 
235 TEST_F(TestParseDpSpec, ParseFailsWithMissingFileId) {
236  m_spec["target"].erase("fileId");
238  ParseDpSpec(m_spec), DpSpecError, MatchesRegex(R"(.*\‍(/target/fileId\).*missing.*)"));
239 }
240 
241 TEST_F(TestParseDpSpec, ParseFailsWithFileIdWrongType) {
242  m_spec["target"]["fileId"] = 0u;
244  DpSpecError,
245  MatchesRegex(R"(.*\‍(/target/fileId\).*must be a string.*)"));
246 }
247 
248 TEST_F(TestParseDpSpec, ParseFailsWithKeywordsBadType) {
249  m_spec["sources"][0]["keywords"][0]["type"] = "";
251  DpSpecError,
252  MatchesRegex(R"(.*\‍(/sources/0/keywords/0/type\).*empty.*)"));
253 }
254 
255 TEST_F(TestParseDpSpec, ParseFailsWithKeywordsNotDefined) {
256  m_spec["sources"][0].erase("keywords");
258  ParseDpSpec(m_spec), DpSpecError, MatchesRegex(R"(.*\‍(/sources/0/keywords\).*missing.*)"));
259 }
260 TEST_F(TestParseDpSpec, ParseSucceedsWithKeywordRulesNotDefined) {
261  m_spec["sources"][2].erase("keywordRules");
262  EXPECT_NO_THROW(ParseDpSpec(m_spec));
263 }
264 
265 TEST_F(TestParseDpSpec, ParseFailsWithMissingSources) {
266  m_spec["target"].erase("source");
267  m_spec["sources"] = nlohmann::json::array();
268 
270  ParseDpSpec(m_spec), DpSpecError, MatchesRegex(R"(.*\‍(/sources\).*At least one.*)"));
271 }
272 
273 TEST_F(TestParseDpSpec, ParseFailsWithUnknownSourceType) {
274  m_spec["sources"][0]["type"] = "unknown";
275 
277  ParseDpSpec(m_spec), DpSpecError, MatchesRegex(R"(.*\‍(/sources/0/type\).*unknown.*)"));
278 }
279 
280 TEST_F(TestParseDpSpec, ParseFailsWithUnknownSourceTypeNotObject) {
281  m_spec["sources"][0] = 0;
282 
284  ParseDpSpec(m_spec), DpSpecError, MatchesRegex(R"(.*\‍(/sources/0\).*object.*)"));
285 }
286 
287 TEST_F(TestParseDpSpec, ParseFailsWithUnknownSourcesWrongType) {
288  m_spec["sources"] = 0;
289 
291  ParseDpSpec(m_spec), DpSpecError, MatchesRegex(R"(.*\‍(/sources\).*array.*)"));
292 }
293 
294 } // namespace daq::json
#define EXPECT_THROW_WITH_MESSAGE(stmt, etype, matcher)
Expect that stmt throws exception of type etype and that the exception message matches matcher.
Definition: expect.hpp:15
std::string id
Definition: dpSpec.hpp:42
Location ParseSourceLocation(std::string const &location_str)
Parse location string from DpSpec into component parts.
Definition: dpSpec.cpp:90
DpSpec ParseDpSpec(Json const &json)
Parse JSON to construct the DpSpec structure.
Definition: dpSpec.cpp:47
std::optional< FitsFileSource > source
Definition: dpSpec.hpp:37
nlohmann::json m_spec
std::vector< SourceTypes > sources
Definition: dpSpec.hpp:44
daq::json::TestParseStartDaqV2Spec _json
TEST_F(TestParseDpSpec, ParseFailsWithUnknownSourcesWrongType)
Definition: testDpSpec.cpp:287
Close representation of the JSON structure but with stronger types.
Definition: dpSpec.hpp:30
Describes parsed location string into its components "host" and "path".
Definition: dpSpec.hpp:58
std::filesystem::path path
Definition: dpSpec.hpp:64
std::string host
Definition: dpSpec.hpp:63
EXPECT_EQ(meta.rr_uri, "zpb.rr://meta")
ASSERT_EQ(meta.keyword_rules.size(), 1u)
auto const & transform