ifw-daq  1.0.0
IFW Data Acquisition modules
testFitsController.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @ingroup daq_ocm_libdaq_test
4  * @copyright 2021 ESO - European Southern Observatory
5  *
6  * @brief Unit test for `daq::FitsControllerImpl`
7  */
8 #include <daq/fitsController.hpp>
9 #include <gtest/gtest.h>
10 #include <gmock/gmock.h>
11 
12 using namespace daq;
13 using namespace ::testing;
14 using namespace std::chrono;
15 
16 //namespace {
17 static daq::fits::UniqueFitsFile s_reclaimed =
19 
20 void FitsfileReclaimer(fitsfile* ptr) noexcept {
21  s_reclaimed.reset();
22  fitsfile* newptr = nullptr;
23  int status = 0;
24  // We have to reopen the fitsfile, otherwise certain fits functions (e.g. fits_get_hdu_nums)
25  // will not report the correct state.
26  fits_reopen_file(ptr, &newptr, &status);
27  fits_close_file(ptr, &status);
28  s_reclaimed.reset(newptr);
29 }
30 
31 constexpr size_t FITS_INITIAL_BUFFER_SIZE = 4 * 2880;
32 
33 //} // namespace
34 
35 /**
36  * Fixture for daq::FitsControllerImpl test
37  *
38  * @ingroup daq_ocm_libdaq_test
39  */
40 class TestFitsController : public ::testing::Test {
41 public:
42  /**
43  * Creates an in-memory FITS file that is reclaimed into @c s_reclaimed when released by
44  * FitsController. This fitsfile is finally closed when @c s_reclaimed is reset.
45  */
46  void SetUp() override {
47  m_properties.dp_name_prefix = "";
48  m_properties.ocm_dppart_root = "/tmp";
49  m_properties.id = "test";
50 
51  s_reclaimed.reset();
52  m_event_log = std::make_shared<ObservableEventLog>();
53  m_fitsbuf = malloc(FITS_INITIAL_BUFFER_SIZE);
54  memset(m_fitsbuf, 0, FITS_INITIAL_BUFFER_SIZE);
55  m_ctl =
56  std::make_unique<FitsControllerImpl>(m_properties, m_event_log, [&](char const* path) {
57  fitsfile* ptr = nullptr;
58  int status = 0;
59  m_fitsbufsize = FITS_INITIAL_BUFFER_SIZE;
60  // note: function will keep references to m_fitsbuf and m_fitsbufsize pointers, so
61  // they must outlive the fitsfile.
62  fits_create_memfile(&ptr, &m_fitsbuf, &m_fitsbufsize, 0, realloc, &status);
63  if (status != 0) {
64  std::cerr<< "Failed to create fits_memfile";
65  std::terminate();
66  }
68  });
69  ASSERT_EQ(State::NotStarted, m_ctl->GetState());
70  }
71 
72  void TearDown() override {
73  m_ctl.reset();
74  s_reclaimed.reset();
75  int status = 0;
76  fits_free_memory(m_fitsbuf, &status);
77  m_fitsbuf = nullptr;
78  }
79 
80 protected:
82  void* m_fitsbuf;
83  size_t m_fitsbufsize;
84  std::shared_ptr<ObservableEventLog> m_event_log;
85  std::unique_ptr<FitsControllerImpl> m_ctl;
86 };
87 
88 
89 TEST_F(TestFitsController, AbortNotStartedSucceeds) {
90  // Run
91  m_ctl->Abort(ErrorPolicy::Strict);
92  EXPECT_EQ(State::Aborted, m_ctl->GetState());
93  ASSERT_FALSE(s_reclaimed) << "There should have been no FITS file to reclaim since not started";
94 }
95 
96 TEST_F(TestFitsController, UpdateKeywordsFailsIfAborted) {
97  // Setup
98  m_ctl->Abort(ErrorPolicy::Strict);
99  ASSERT_EQ(State::Aborted, m_ctl->GetState());
100  // Run
101  EXPECT_THROW(m_ctl->UpdateKeywords({}),
102  std::runtime_error);
103 }
104 
105 TEST_F(TestFitsController, AddCommentFailsIfAborted) {
106  // Setup
107  m_ctl->Abort(ErrorPolicy::Strict);
108  ASSERT_EQ(State::Aborted, m_ctl->GetState());
109  // Run
110  EXPECT_THROW(m_ctl->AddComment({}),
111  std::runtime_error);
112 }
113 
114 TEST_F(TestFitsController, UpdateKeywordsFailsIfStopped) {
115  // Setup
116  m_ctl->Start();
117  m_ctl->Stop(ErrorPolicy::Strict);
118  ASSERT_EQ(State::Stopped, m_ctl->GetState());
119  // Run
120  EXPECT_THROW(m_ctl->UpdateKeywords({}),
121  std::runtime_error);
122 }
123 
124 TEST_F(TestFitsController, AddCommentFailsIfStopped) {
125  // Setup
126  m_ctl->Start();
127  m_ctl->Stop(ErrorPolicy::Strict);
128  ASSERT_EQ(State::Stopped, m_ctl->GetState());
129  // Run
130  EXPECT_THROW(m_ctl->AddComment({}),
131  std::runtime_error);
132 }
133 
134 TEST_F(TestFitsController, StartAlreadyStartedFails) {
135  // Setup
136  m_ctl->Start();
137  // Run
138  EXPECT_THROW(m_ctl->Start(),
139  std::runtime_error);
140 }
141 
142 TEST_F(TestFitsController, StopAlreadyStoppedFails) {
143  // Setup
144  m_ctl->Start();
145  m_ctl->Stop(ErrorPolicy::Strict);
146 
147  // Run
148  EXPECT_THROW(m_ctl->Stop(ErrorPolicy::Strict),
149  std::runtime_error);
150 }
151 
152 TEST_F(TestFitsController, AbortAlreadyStoppedFails) {
153  // Setup
154  m_ctl->Start();
155  m_ctl->Stop(ErrorPolicy::Strict);
156 
157  // Run
158  EXPECT_THROW(m_ctl->Abort(ErrorPolicy::Strict),
159  std::runtime_error);
160 }
161 
162 
163 TEST_F(TestFitsController, AbortAcquiringSucceeds) {
164  // Setup
165  m_ctl->Start();
166 
167  // Run
168  m_ctl->Abort(ErrorPolicy::Strict);
169  EXPECT_EQ(State::Aborted, m_ctl->GetState());
170  // There should be no result
171  auto res = m_ctl->GetResult();
172  ASSERT_FALSE(res);
173  ASSERT_TRUE(s_reclaimed) << "Abort() should have closed FITS file";
174 }
175 
176 TEST_F(TestFitsController, StartCreatesFitsfile) {
177  // Run
178  EXPECT_FALSE(m_ctl->GetFitsfile());
179 
180  m_ctl->Start();
181  EXPECT_EQ(State::Acquiring, m_ctl->GetState());
182 
183  EXPECT_TRUE(m_ctl->GetFitsfile());
184  // There should be no result yet
185  auto res = m_ctl->GetResult();
186  ASSERT_FALSE(res);
187 }
188 
189 TEST_F(TestFitsController, StopClosesFitsfileAndProduceResult) {
190  // Setup
191  m_ctl->Start();
192  ASSERT_EQ(State::Acquiring, m_ctl->GetState());
193 
194  // Run
195  m_ctl->Stop(ErrorPolicy::Strict);
196  EXPECT_EQ(State::Stopped, m_ctl->GetState());
197 
198  // There should be a result at this point
199  auto res = m_ctl->GetResult();
200  ASSERT_TRUE(res);
201  EXPECT_NE(res->origin, "");
202  ASSERT_TRUE(std::holds_alternative<std::string>(res->info));
203  EXPECT_THAT(std::get<std::string>(res->info), EndsWith(":/tmp/test_ocm.fits"));
204  ASSERT_TRUE(s_reclaimed.get());
205 
206  // Check content of FITS file
207  int status = 0;
208  {
209 
210  int hdu_num = -1;
211  EXPECT_EQ(0, fits_get_num_hdus(s_reclaimed.get(), &hdu_num, &status));
212  EXPECT_EQ(1, hdu_num);
213  }
214  {
215  int hdu_type = -1;
216  EXPECT_EQ(0, fits_get_hdu_type(s_reclaimed.get(), &hdu_type, &status));
217  EXPECT_EQ(IMAGE_HDU, hdu_type);
218  }
219  // @todo Validate keywords using dictionary system (when that is available)
220 }
TestFitsController::m_fitsbuf
void * m_fitsbuf
Definition: testFitsController.cpp:82
TestFitsController::m_properties
DaqProperties m_properties
Definition: testFitsController.cpp:81
TestFitsController::m_fitsbufsize
size_t m_fitsbufsize
Definition: testFitsController.cpp:83
TestFitsController::m_ctl
std::unique_ptr< FitsControllerImpl > m_ctl
Definition: testFitsController.cpp:85
daq::DaqProperties
Structure carrying properties needed to start a DataAcquisition.
Definition: daqProperties.hpp:28
daq::TEST_F
TEST_F(TestSource, Constructors)
Definition: testSource.cpp:34
TestFitsController::SetUp
void SetUp() override
Creates an in-memory FITS file that is reclaimed into s_reclaimed when released by FitsController.
Definition: testFitsController.cpp:46
daq
Definition: daqController.cpp:18
daq::fits::UniqueFitsFile
std::unique_ptr< fitsfile, void(*)(fitsfile *) noexcept > UniqueFitsFile
Defines unique ownership type to cfitsio fitsfile.
Definition: cfitsio.hpp:46
fitsController.hpp
Contains declaration for for FitsController.
FITS_INITIAL_BUFFER_SIZE
constexpr size_t FITS_INITIAL_BUFFER_SIZE
Definition: testFitsController.cpp:31
TestFitsController::m_event_log
std::shared_ptr< ObservableEventLog > m_event_log
Definition: testFitsController.cpp:84
TestFitsController
Fixture for daq::FitsControllerImpl test.
Definition: testFitsController.cpp:40
TestFitsController::TearDown
void TearDown() override
Definition: testFitsController.cpp:72
FitsfileReclaimer
void FitsfileReclaimer(fitsfile *ptr) noexcept
Definition: testFitsController.cpp:20
daq::State::NotStarted
@ NotStarted
Initial state of data acquisition.
daq::fits::DefaultClose
void DefaultClose(fitsfile *ptr) noexcept
Default close function that is used by UniqueFitsFile as a deleter.
Definition: cfitsio.cpp:23