ifw-daq  2.1.0-pre1
IFW Data Acquisition modules
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 
19 #include "mock/metadaqifMock.hpp"
20 #include "testAsyncOpBase.hpp"
21 
22 using namespace daq;
23 using namespace ::testing;
24 
25 /**
26  * @ingroup daq_ocm_libdaq_test
27  *
28  * Note: TestAsyncOpBase set
29  */
31  void SetUp() override {
33 
34  m_keywords = R"(
35  [
36  {
37  "type":"valueKeyword",
38  "name":"OBJECT",
39  "value":"OBJECT,SKY"
40  },
41  {
42  "type":"esoKeyword",
43  "name":"OBS TPLNO",
44  "value":2
45  }
46  ]
47  )";
48  }
49  std::string m_keywords;
50  std::string m_empty;
51 };
52 
54  std::vector<std::string> meta_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
55  std::vector<std::string> meta_reply_files_2;
56 
57  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
58  auto reply_mock = std::make_shared<DaqStopReplyMock>();
59  EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
60  EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return(m_keywords));
61 
62  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
63  auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
64  EXPECT_CALL(*reply_mock2, getFiles()).WillRepeatedly(Return(meta_reply_files_2));
65  EXPECT_CALL(*reply_mock2, getKeywords()).WillRepeatedly(Return(m_empty));
66  EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
67  EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
68  .WillOnce(Return(ByMove(reply_promise2.get_future())));
69 
70  boost::promise<std::shared_ptr<recif::RecStatus>> prim_reply_promise_1;
71  boost::promise<std::shared_ptr<recif::RecStatus>> prim_reply_promise_2;
72  EXPECT_CALL(*m_prim_rr_client, RecStop())
73  .WillOnce(Return(ByMove(prim_reply_promise_1.get_future())));
74  EXPECT_CALL(*m_prim_rr_client2, RecStop())
75  .WillOnce(Return(ByMove(prim_reply_promise_2.get_future())));
76 
77  std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
78  std::vector<std::string> prim_reply_files_2;
79  auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
80  auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
81  EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
82  EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
83 
84  // Run
85  auto fut = op::InitiateOperation<op::StopAsync>(ErrorPolicy::Strict, MakeParams());
86  ASSERT_FALSE(fut.is_ready());
87 
88  // "Send reply"
89  reply_promise.set_value(reply_mock);
90  reply_promise2.set_value(reply_mock2);
91  prim_reply_promise_1.set_value(prim_reply_mock1);
92  prim_reply_promise_2.set_value(prim_reply_mock2);
93 
94  // Execute handlers
95  MakeTestProgress(m_io_ctx, &fut);
96 
97  ASSERT_TRUE(fut.is_ready());
98  ASSERT_FALSE(fut.has_exception()) << "Future has unexpected exception!";
99  auto result = fut.get();
100  EXPECT_EQ(result.result.size(),
101  1u /* 1 set of keywords from m_keywords */ + meta_reply_files_1.size() +
102  prim_reply_files_1.size());
103 }
104 
105 TEST_F(TestAsyncOpStop, StopReturnsInvalidJsonKeywordsSucceedsIfTolerant) {
106  std::vector<std::string> meta_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
107  std::vector<std::string> meta_reply_files_2;
108 
109  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
110  auto reply_mock = std::make_shared<DaqStopReplyMock>();
111  EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
112  EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return("this is not JSON"));
113 
114  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
115  auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
116  EXPECT_CALL(*reply_mock2, getFiles()).WillRepeatedly(Return(meta_reply_files_2));
117  EXPECT_CALL(*reply_mock2, getKeywords()).WillRepeatedly(Return(m_empty));
118  EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
119  EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
120  .WillOnce(Return(ByMove(reply_promise2.get_future())));
121 
122  EXPECT_CALL(*m_prim_rr_client, RecStop())
123  .WillOnce(Return(ByMove(m_recstatus_promise1.get_future())));
124  EXPECT_CALL(*m_prim_rr_client2, RecStop())
125  .WillOnce(Return(ByMove(m_recstatus_promise2.get_future())));
126  std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
127  std::vector<std::string> prim_reply_files_2;
128  auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
129  auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
130  EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
131  EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
132 
133  // Run
134  auto fut = op::InitiateOperation<op::StopAsync>(ErrorPolicy::Tolerant, MakeParams());
135  ASSERT_FALSE(fut.is_ready());
136 
137  // "Send reply"
138  reply_promise.set_value(reply_mock);
139  reply_promise2.set_value(reply_mock2);
140  m_recstatus_promise1.set_value(prim_reply_mock1);
141  m_recstatus_promise2.set_value(prim_reply_mock2);
142 
143  // Execute handlers
144  MakeTestProgress(m_io_ctx, &fut);
145 
146  ASSERT_TRUE(fut.is_ready());
147  ASSERT_FALSE(fut.has_exception()) << "Future should have an exception from JSON decoding error";
148  auto result = fut.get();
149  EXPECT_EQ(result.result.size(), meta_reply_files_1.size() + prim_reply_files_1.size())
150  << "Expected 0 keywords from failed parsing";
151 }
152 
153 TEST_F(TestAsyncOpStop, StopReturnsInvalidJsonKeywordsFails) {
154  std::vector<std::string> meta_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
155  std::vector<std::string> meta_reply_files_2;
156 
157  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
158  auto reply_mock = std::make_shared<DaqStopReplyMock>();
159  EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
160  EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return("this is not JSON"));
161 
162  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
163  auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
164  EXPECT_CALL(*reply_mock2, getFiles()).WillRepeatedly(Return(meta_reply_files_2));
165  EXPECT_CALL(*reply_mock2, getKeywords()).WillRepeatedly(Return(m_empty));
166  EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
167  EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
168  .WillOnce(Return(ByMove(reply_promise2.get_future())));
169 
170  EXPECT_CALL(*m_prim_rr_client, RecStop())
171  .WillOnce(Return(ByMove(m_recstatus_promise1.get_future())));
172  EXPECT_CALL(*m_prim_rr_client2, RecStop())
173  .WillOnce(Return(ByMove(m_recstatus_promise2.get_future())));
174  std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
175  std::vector<std::string> prim_reply_files_2;
176  auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
177  auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
178  EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
179  EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
180 
181  // Run
182  auto fut = op::InitiateOperation<op::StopAsync>(ErrorPolicy::Strict, MakeParams());
183  ASSERT_FALSE(fut.is_ready());
184 
185  // "Send reply"
186  reply_promise.set_value(reply_mock);
187  reply_promise2.set_value(reply_mock2);
188  m_recstatus_promise1.set_value(prim_reply_mock1);
189  m_recstatus_promise2.set_value(prim_reply_mock2);
190 
191  // Execute handlers
192  MakeTestProgress(m_io_ctx, &fut);
193 
194  ASSERT_TRUE(fut.is_ready());
195  ASSERT_TRUE(fut.has_exception()) << "Future should have an exception from JSON decoding error";
196  EXPECT_THROW(fut.get(), daq::DaqSourceErrors);
197 }
198 
199 /**
200  * m_meta_rr_client Will succeed.
201  * m_meta_rr_client2 will fail.
202  */
203 TEST_F(TestAsyncOpStop, StopMetaFailsReturnsExceptionalFuture) {
204  std::vector<std::string> meta_reply_files_1;
205 
206  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
207  auto reply_mock = std::make_shared<DaqStopReplyMock>();
208  EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
209  EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return("")); // no keywords
210 
211  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
212  auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
213  EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
214  EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
215  .WillOnce(Return(ByMove(reply_promise2.get_future())));
216 
217  EXPECT_CALL(*m_prim_rr_client, RecStop())
218  .WillOnce(Return(ByMove(m_recstatus_promise1.get_future())));
219  EXPECT_CALL(*m_prim_rr_client2, RecStop())
220  .WillOnce(Return(ByMove(m_recstatus_promise2.get_future())));
221  std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
222  std::vector<std::string> prim_reply_files_2;
223  auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
224  auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
225  EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
226  EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
227 
228  // Run
229  auto fut = op::InitiateOperation<op::StopAsync>(ErrorPolicy::Strict, MakeParams());
230  ASSERT_FALSE(fut.is_ready());
231 
232  // "Send reply"
233  reply_promise.set_value(reply_mock);
234  reply_promise2.set_exception(metadaqif::DaqException(m_id, "message"));
235  m_recstatus_promise1.set_value(prim_reply_mock1);
236  m_recstatus_promise2.set_value(prim_reply_mock2);
237 
238  // Execute handlers
239  MakeTestProgress(m_io_ctx, &fut);
240 
241  ASSERT_TRUE(fut.is_ready());
242  EXPECT_THROW(fut.get(), daq::DaqSourceErrors);
243 }
244 
245 TEST_F(TestAsyncOpStop, StopMetaFailsReturnsSuccessWithTolerantPolicy) {
246  std::vector<std::string> meta_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
247 
248  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise;
249  auto reply_mock = std::make_shared<DaqStopReplyMock>();
250  EXPECT_CALL(*reply_mock, getFiles()).WillRepeatedly(Return(meta_reply_files_1));
251  EXPECT_CALL(*reply_mock, getKeywords()).WillRepeatedly(Return("")); // no keywords
252 
253  boost::promise<std::shared_ptr<metadaqif::DaqStopReply>> reply_promise2;
254  auto reply_mock2 = std::make_shared<DaqStopReplyMock>();
255  EXPECT_CALL(*m_meta_rr_client, StopDaq(_)).WillOnce(Return(ByMove(reply_promise.get_future())));
256  EXPECT_CALL(*m_meta_rr_client2, StopDaq(_))
257  .WillOnce(Return(ByMove(reply_promise2.get_future())));
258  EXPECT_CALL(*m_prim_rr_client, RecStop())
259  .WillOnce(Return(ByMove(m_recstatus_promise1.get_future())));
260  EXPECT_CALL(*m_prim_rr_client2, RecStop())
261  .WillOnce(Return(ByMove(m_recstatus_promise2.get_future())));
262  std::vector<std::string> prim_reply_files_1 = {"host@:/some/path", "host@:/some/path2"};
263  std::vector<std::string> prim_reply_files_2;
264  auto prim_reply_mock1 = std::make_shared<RecStatusMock>();
265  auto prim_reply_mock2 = std::make_shared<RecStatusMock>();
266  EXPECT_CALL(*prim_reply_mock1, getDpFiles()).WillRepeatedly(Return(prim_reply_files_1));
267  EXPECT_CALL(*prim_reply_mock2, getDpFiles()).WillRepeatedly(Return(prim_reply_files_2));
268 
269  // Run
270  auto fut = op::InitiateOperation<op::StopAsync>(ErrorPolicy::Tolerant, MakeParams());
271  ASSERT_FALSE(fut.is_ready());
272 
273  // "Send reply"
274  reply_promise.set_value(reply_mock);
275  reply_promise2.set_exception(metadaqif::DaqException(m_id, "message"));
276  m_recstatus_promise1.set_value(prim_reply_mock1);
277  m_recstatus_promise2.set_value(prim_reply_mock2);
278 
279  // Execute handlers
280  MakeTestProgress(m_io_ctx, &fut);
281 
282  ASSERT_TRUE(fut.is_ready());
283  EXPECT_FALSE(fut.has_exception());
284  auto result = fut.get();
285  EXPECT_TRUE(result.error);
286  EXPECT_EQ(result.result.size(), meta_reply_files_1.size() + prim_reply_files_1.size());
287 }
TestAsyncOpStop
Note: TestAsyncOpBase set.
Definition: testAsyncOpStop.cpp:30
initiate.hpp
Contains declarations for the helper functions to initiate operations.
TestAsyncOpBase::SetUp
void SetUp() override
Definition: testAsyncOpBase.cpp:23
metadaqifMock.hpp
Mockup of metadaqif classes.
stop.hpp
Contains declaration for the StopAsync operation.
daq::DaqSourceErrors
Exception thrown to carry reply errors.
Definition: error.hpp:84
daq
Definition: asyncProcess.cpp:15
config.hpp
TestAsyncOpStop::m_keywords
std::string m_keywords
Definition: testAsyncOpStop.cpp:49
TestAsyncOpStop::SetUp
void SetUp() override
Definition: testAsyncOpStop.cpp:31
TestAsyncOpStop::m_empty
std::string m_empty
Definition: testAsyncOpStop.cpp:50
testAsyncOpBase.hpp
Contains declaration for async operations shared base class.
daq::TEST_F
TEST_F(TestDpmDaqController, StatusUpdateInNotScheduledSucceeds)
Definition: testDpmDaqController.cpp:60
TestAsyncOpBase
Base fixture for async operation tests.
Definition: testAsyncOpBase.hpp:38
daq::ErrorPolicy::Strict
@ Strict
Any error is considered fatal and may lead to the operation being aborted.
error.hpp
Contains error related declarations for DAQ.
MakeTestProgress
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:42