ifw-daq 3.1.0
IFW Data Acquisition modules
Loading...
Searching...
No Matches
testAsyncOpStop.cpp
Go to the documentation of this file.
1/**
2 * @file
3 * @ingroup daq_ocm_libdaq_test
4 * @copyright 2022 ESO - European Southern Observatory
5 *
6 * @brief Unit test for daq::op::StopAsync
7 */
8#include <daq/config.hpp>
9
10#include <gmock/gmock.h>
11#include <gtest/gtest.h>
12#include <log4cplus/logger.h>
13#include <nlohmann/json.hpp>
14
15#include <daq/error.hpp>
16#include <daq/op/initiate.hpp>
17#include <daq/op/stop.hpp>
18
21
22#include "testAsyncOpBase.hpp"
23#include "utils.hpp"
24
25using namespace daq;
26using namespace ::testing;
27
28/**
29 * @ingroup daq_ocm_libdaq_test
30 *
31 * Note: TestAsyncOpBase set
32 */
34 void SetUp() override {
36
37 m_keywords = R"(
38 [
39 {
40 "type":"valueKeyword",
41 "name":"OBJECT",
42 "value":"OBJECT,SKY"
43 },
44 {
45 "type":"esoKeyword",
46 "name":"OBS TPLNO",
47 "value":2
48 }
49 ]
50 )";
51 }
52 std::string m_keywords;
53 std::string m_empty;
54};
55
57 std::vector<std::string> meta_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
58 std::vector<std::string> meta_reply_files_2;
59
60 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
61 auto reply_mock = std::make_shared<DaqStopReplyMock>();
62 EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
63 EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return(m_keywords));
64
65 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
66 auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
67 EXPECT_CALL(*reply_mock2, getFiles()).WillRepeatedly(Return(meta_reply_files_2));
68 EXPECT_CALL(*reply_mock2, getKeywords()).WillRepeatedly(Return(m_empty));
69 EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
70 EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
71 .WillOnce(Return(ByMove(reply_promise2.get_future())));
72
73 boost::promise<std::shared_ptr<recif::RecStatus>> prim_reply_promise_1;
74 boost::promise<std::shared_ptr<recif::RecStatus>> prim_reply_promise_2;
75 EXPECT_CALL(*m_prim_rr_client, RecStop())
76 .WillOnce(Return(ByMove(prim_reply_promise_1.get_future())));
77 EXPECT_CALL(*m_prim_rr_client2, RecStop())
78 .WillOnce(Return(ByMove(prim_reply_promise_2.get_future())));
79
80 std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
81 std::vector<std::string> prim_reply_files_2;
82 auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
83 auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
84 EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
85 EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
86
87 // Run
88 auto fut = op::InitiateOperation<op::StopAsync>(m_executor, ErrorPolicy::Strict, MakeParams());
89 ASSERT_FALSE(fut.is_ready());
90
91 // "Send reply"
92 reply_promise.set_value(reply_mock);
93 reply_promise2.set_value(reply_mock2);
94 prim_reply_promise_1.set_value(prim_reply_mock1);
95 prim_reply_promise_2.set_value(prim_reply_mock2);
96
97 // Execute handlers
98 MakeTestProgress(m_io_ctx, &fut);
99
100 ASSERT_TRUE(fut.is_ready());
101 ASSERT_FALSE(fut.has_exception()) << "Future has unexpected exception!";
102 auto result = fut.get();
103 EXPECT_EQ(result.result.size(),
104 1u /* 1 set of keywords from m_keywords */ + meta_reply_files_1.size() +
105 prim_reply_files_1.size());
106}
107
108TEST_F(TestAsyncOpStop, StopReturnsInvalidJsonKeywordsSucceedsIfTolerant) {
109 std::vector<std::string> meta_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
110 std::vector<std::string> meta_reply_files_2;
111
112 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
113 auto reply_mock = std::make_shared<DaqStopReplyMock>();
114 EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
115 EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return("this is not JSON"));
116
117 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
118 auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
119 EXPECT_CALL(*reply_mock2, getFiles()).WillRepeatedly(Return(meta_reply_files_2));
120 EXPECT_CALL(*reply_mock2, getKeywords()).WillRepeatedly(Return(m_empty));
121 EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
122 EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
123 .WillOnce(Return(ByMove(reply_promise2.get_future())));
124
125 EXPECT_CALL(*m_prim_rr_client, RecStop())
126 .WillOnce(Return(ByMove(m_recstatus_promise1.get_future())));
127 EXPECT_CALL(*m_prim_rr_client2, RecStop())
128 .WillOnce(Return(ByMove(m_recstatus_promise2.get_future())));
129 std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
130 std::vector<std::string> prim_reply_files_2;
131 auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
132 auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
133 EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
134 EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
135
136 // Run
137 auto fut =
138 op::InitiateOperation<op::StopAsync>(m_executor, ErrorPolicy::Tolerant, MakeParams());
139 ASSERT_FALSE(fut.is_ready());
140
141 // "Send reply"
142 reply_promise.set_value(reply_mock);
143 reply_promise2.set_value(reply_mock2);
144 m_recstatus_promise1.set_value(prim_reply_mock1);
145 m_recstatus_promise2.set_value(prim_reply_mock2);
146
147 // Execute handlers
148 MakeTestProgress(m_io_ctx, &fut);
149
150 ASSERT_TRUE(fut.is_ready());
151 ASSERT_FALSE(fut.has_exception()) << "Future should have an exception from JSON decoding error";
152 auto result = fut.get();
153 EXPECT_EQ(result.result.size(), prim_reply_files_1.size())
154 << "Expected nothing from meta source";
155
156 EXPECT_EQ(m_alerts.set.size(), 1u);
157}
158
159TEST_F(TestAsyncOpStop, StopReturnsInvalidJsonKeywordsFails) {
160 std::vector<std::string> meta_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
161 std::vector<std::string> meta_reply_files_2;
162
163 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
164 auto reply_mock = std::make_shared<DaqStopReplyMock>();
165 EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
166 EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return("this is not JSON"));
167
168 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
169 auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
170 EXPECT_CALL(*reply_mock2, getFiles()).WillRepeatedly(Return(meta_reply_files_2));
171 EXPECT_CALL(*reply_mock2, getKeywords()).WillRepeatedly(Return(m_empty));
172 EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
173 EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
174 .WillOnce(Return(ByMove(reply_promise2.get_future())));
175
176 EXPECT_CALL(*m_prim_rr_client, RecStop())
177 .WillOnce(Return(ByMove(m_recstatus_promise1.get_future())));
178 EXPECT_CALL(*m_prim_rr_client2, RecStop())
179 .WillOnce(Return(ByMove(m_recstatus_promise2.get_future())));
180 std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
181 std::vector<std::string> prim_reply_files_2;
182 auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
183 auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
184 EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
185 EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
186
187 // Run
188 auto fut = op::InitiateOperation<op::StopAsync>(m_executor, ErrorPolicy::Strict, MakeParams());
189 ASSERT_FALSE(fut.is_ready());
190
191 // "Send reply"
192 reply_promise.set_value(reply_mock);
193 reply_promise2.set_value(reply_mock2);
194 m_recstatus_promise1.set_value(prim_reply_mock1);
195 m_recstatus_promise2.set_value(prim_reply_mock2);
196
197 // Execute handlers
198 MakeTestProgress(m_io_ctx, &fut);
199
200 ASSERT_TRUE(fut.is_ready());
201 ASSERT_TRUE(fut.has_exception()) << "Future should have an exception from JSON decoding error";
202 EXPECT_THROW(fut.get(), daq::DaqSourceErrors);
203 EXPECT_EQ(m_alerts.set.size(), 1u);
204}
205
206TEST_F(TestAsyncOpStop, StopReturnsUnknownKeywordsFails) {
207 KeywordFormatterMock kw_fmt_mock;
208
209 std::vector<std::string> meta_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
210 std::vector<std::string> meta_reply_files_2;
211
212 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
213 auto reply_mock = std::make_shared<DaqStopReplyMock>();
214 EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
215 EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return(m_keywords));
216 auto object_kw = fits::ValueKeyword("OBJECT", "OBJECT,SKY");
217 auto obs_tplno_kw = fits::EsoKeyword("OBS TPLNO", static_cast<std::uint64_t>(2u));
218 EXPECT_CALL(kw_fmt_mock, Format(fits::KeywordVariant(object_kw)))
219 .WillOnce(Return(fits::Format(object_kw)));
220 EXPECT_CALL(kw_fmt_mock, Format(fits::KeywordVariant(obs_tplno_kw)))
221 .WillOnce(Throw(fits::UnknownKeyword("OBS TPLNO", {})));
222
223 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
224 auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
225 EXPECT_CALL(*reply_mock2, getFiles()).WillRepeatedly(Return(meta_reply_files_2));
226 EXPECT_CALL(*reply_mock2, getKeywords()).WillRepeatedly(Return(m_empty));
227 EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
228 EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
229 .WillOnce(Return(ByMove(reply_promise2.get_future())));
230
231 EXPECT_CALL(*m_prim_rr_client, RecStop())
232 .WillOnce(Return(ByMove(m_recstatus_promise1.get_future())));
233 EXPECT_CALL(*m_prim_rr_client2, RecStop())
234 .WillOnce(Return(ByMove(m_recstatus_promise2.get_future())));
235 std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
236 std::vector<std::string> prim_reply_files_2;
237 auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
238 auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
239 EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
240 EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
241
242 // Run
243 auto fut = op::InitiateOperation<op::StopAsync>(
244 m_executor, ErrorPolicy::Strict, MakeParams(&kw_fmt_mock));
245 ASSERT_FALSE(fut.is_ready());
246
247 // "Send reply"
248 reply_promise.set_value(reply_mock);
249 reply_promise2.set_value(reply_mock2);
250 m_recstatus_promise1.set_value(prim_reply_mock1);
251 m_recstatus_promise2.set_value(prim_reply_mock2);
252
253 // Execute handlers
254 MakeTestProgress(m_io_ctx, &fut);
255
256 ASSERT_TRUE(fut.is_ready());
257 ASSERT_TRUE(fut.has_exception()) << "Future should have an exception from unknown keyword";
258 EXPECT_EQ(m_alerts.set.size(), 1u);
259
260 for (auto& s : m_meta_sources) {
261 EXPECT_EQ(s.GetState(), State::Stopped);
262 }
263}
264
265/**
266 * m_meta_rr_client Will succeed.
267 * m_meta_rr_client2 will fail.
268 */
269TEST_F(TestAsyncOpStop, StopMetaFailsReturnsExceptionalFuture) {
270 std::vector<std::string> meta_reply_files_1;
271
272 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
273 auto reply_mock = std::make_shared<DaqStopReplyMock>();
274 EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
275 EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return("")); // no keywords
276
277 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
278 auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
279 EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
280 EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
281 .WillOnce(Return(ByMove(reply_promise2.get_future())));
282
283 EXPECT_CALL(*m_prim_rr_client, RecStop())
284 .WillOnce(Return(ByMove(m_recstatus_promise1.get_future())));
285 EXPECT_CALL(*m_prim_rr_client2, RecStop())
286 .WillOnce(Return(ByMove(m_recstatus_promise2.get_future())));
287 std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
288 std::vector<std::string> prim_reply_files_2;
289 auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
290 auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
291 EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
292 EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
293
294 // Run
295 auto fut = op::InitiateOperation<op::StopAsync>(m_executor, ErrorPolicy::Strict, MakeParams());
296 ASSERT_FALSE(fut.is_ready());
297
298 // "Send reply"
299 reply_promise.set_value(reply_mock);
300 reply_promise2.set_exception(metadaqif::DaqException(m_id, "message"));
301 m_recstatus_promise1.set_value(prim_reply_mock1);
302 m_recstatus_promise2.set_value(prim_reply_mock2);
303
304 // Execute handlers
305 MakeTestProgress(m_io_ctx, &fut);
306
307 ASSERT_TRUE(fut.is_ready());
308 EXPECT_THROW(fut.get(), daq::DaqSourceErrors);
309 EXPECT_EQ(m_alerts.set.size(), 1u);
310}
311
312TEST_F(TestAsyncOpStop, StopMetaFailsReturnsSuccessWithTolerantPolicy) {
313 std::vector<std::string> meta_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
314
315 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
316 auto reply_mock = std::make_shared<DaqStopReplyMock>();
317 EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
318 EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return("")); // no keywords
319
320 boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
321 auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
322 EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
323 EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
324 .WillOnce(Return(ByMove(reply_promise2.get_future())));
325 EXPECT_CALL(*m_prim_rr_client, RecStop())
326 .WillOnce(Return(ByMove(m_recstatus_promise1.get_future())));
327 EXPECT_CALL(*m_prim_rr_client2, RecStop())
328 .WillOnce(Return(ByMove(m_recstatus_promise2.get_future())));
329 std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
330 std::vector<std::string> prim_reply_files_2;
331 auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
332 auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
333 EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
334 EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
335
336 // Run
337 auto fut =
338 op::InitiateOperation<op::StopAsync>(m_executor, ErrorPolicy::Tolerant, MakeParams());
339 ASSERT_FALSE(fut.is_ready());
340
341 // "Send reply"
342 reply_promise.set_value(reply_mock);
343 reply_promise2.set_exception(metadaqif::DaqException(m_id, "message"));
344 m_recstatus_promise1.set_value(prim_reply_mock1);
345 m_recstatus_promise2.set_value(prim_reply_mock2);
346
347 // Execute handlers
348 MakeTestProgress(m_io_ctx, &fut);
349
350 ASSERT_TRUE(fut.is_ready());
351 EXPECT_FALSE(fut.has_exception());
352 auto result = fut.get();
353 EXPECT_TRUE(result.error);
354 EXPECT_EQ(result.result.size(), meta_reply_files_1.size() + prim_reply_files_1.size());
355}
356
357TEST_F(TestAsyncOpStop, StopIgnoresAlreadyStoppedSources) {
358 // Test that sending repeated stop command are not sent to sources that are known to be stopped.
359 for (auto& s : m_prim_sources) {
360 s.SetState(State::Stopped);
361 }
362 for (auto& s : m_meta_sources) {
363 s.SetState(State::Stopped);
364 }
365 auto fut =
366 op::InitiateOperation<op::StopAsync>(m_executor, ErrorPolicy::Tolerant, MakeParams());
367 MakeTestProgress(m_io_ctx, &fut);
368 ASSERT_TRUE(fut.is_ready());
369 auto result = fut.get();
370 EXPECT_EQ(result.result.size(), 0u);
371}
Exception thrown to carry reply errors.
Definition: error.hpp:85
Indicates keyword is unknown and cannot be formatted.
Definition: keyword.hpp:543
Contains error related declarations for DAQ.
std::string m_empty
std::string m_keywords
void SetUp() override
void SetUp() override
void MakeTestProgress(boost::asio::io_context &io_ctx, Future *fut=nullptr)
Test helper that progress the test by executing pending jobs and optionally wait for a future to be r...
Definition: utils.hpp:44
Base fixture for async operation tests.
Note: TestAsyncOpBase set.
Contains declarations for the helper functions to initiate operations.
Mockup of metadaqif classes.
LiteralKeyword Format(KeywordVariant const &keyword)
Definition: keyword.cpp:782
std::variant< ValueKeyword, EsoKeyword, LiteralKeyword > KeywordVariant
The different variants of keywords that are supported.
Definition: keyword.hpp:409
BasicKeyword< ValueKeywordTraits > ValueKeyword
Standard FITS value keyword.
Definition: keyword.hpp:339
BasicKeyword< EsoKeywordTraits > EsoKeyword
ESO hiearchical keyword.
Definition: keyword.hpp:346
Contains declaration for the StopAsync operation.
Contains declaration for async operations shared base class.
TEST_F(TestAsyncOpStop, Stop)
EXPECT_EQ(meta.rr_uri, "zpb.rr://meta")
ASSERT_TRUE(std::holds_alternative< OlasReceiver >(spec.receivers[0]))
Defines shared test utilities.