API
 
Loading...
Searching...
No Matches
logFileRaw_test.cpp
Go to the documentation of this file.
1/** \file logFileRaw_test.hpp
2 * \brief Tests for the logFileRaw class
3 * \ingroup logger_files
4 */
5
6#include "../../../tests/testXWC.hpp"
7
8#include "../logFileRaw.hpp"
9
10namespace libXWCTest
11{
12
13/** \defgroup logger_unit_test libXWC::logger Unit Tests
14 * \ingroup unit_test
15 */
16
17/// Namespace for XWC::logger tests
18/** \ingroup logger_unit_test
19 *
20 */
21namespace loggerTest
22{
23
24/** \defgroup logFileRaw_unit_test logFileRaw Unit Tests
25 * \ingroup logger_unit_test
26 */
27
28/// Namespace for XWC::logger::logFileRaw tests
29/** \ingroup logFileRaw_unit_test
30 *
31 */
33{
34
35class logFileRawTest : public MagAOX::logger::logFileRaw<XWC_DEFAULT_VERBOSITY>
36{
37 public:
38 std::string testPath;
39
41 {
42 m_logPath = "/tmp";
43
45 }
46
47 explicit logFileRawTest( const std::string &lp )
48 {
49 m_logPath = lp;
50
52 }
53
55 {
56 return createFile( ts );
57 }
58};
59
60/// Construction of logFileRaw
61/**
62 * \ingroup logFileRaw_unit_test
63 */
64TEST_CASE( "Construction of logFileRaw", "[libMagAOX::logger::logFileRaw]" )
65{
66 SECTION( "basic construction and member access" )
67 {
69
70 REQUIRE( lfr.logPath() == "." );
71 REQUIRE( lfr.logName() == "xlog" );
72 REQUIRE( lfr.logExt() == MAGAOX_default_logExt );
73 REQUIRE( lfr.maxLogSize() == MAGAOX_default_max_logSize );
74
75 lfr.logPath( "/newp/test/x" );
76 REQUIRE( lfr.logPath() == "/newp/test/x" );
77
78 lfr.logName( "newdev" );
79 REQUIRE( lfr.logName() == "newdev" );
80
81 lfr.logExt( "bintel" );
82 REQUIRE( lfr.logExt() == "bintel" );
83
84 lfr.maxLogSize( 10 );
85 REQUIRE( lfr.maxLogSize() == 10 );
86 }
87}
88
89/// Creating a log file
90/**
91 * \ingroup logFileRaw_unit_test
92 */
93TEST_CASE( "Creating a log file", "[libMagAOX::logger::logFileRaw]" )
94{
95 // clang-format off
96 #ifdef XWCTEST_DOXYGEN_REF_PROTECTED
97 logFileRaw lfr;
98 flatlogs::timespecX ts1( 1732170780, 1 );
99 lfr.createFile( ts1 );
100 lfr.logName();
101 lfr.logExt();
102 lfr.m_logPath;
103 lfr.m_logName;
104 #endif
105 // clang-format on
106
107 SECTION( "Two valid timestamps" )
108 {
109 logFileRawTest lfr;
110
111 // safety check to make sure we don't delete all of /tmp
112 if( lfr.testPath == "/tmp" )
113 {
114 std::cerr << "\nTESTING-ERROR: testPath is just /tmp, so logName is null. Can't go on\n";
115 std::cerr << __FILE__ << ' ' << __LINE__ << "\n\n";
116 REQUIRE( false );
117 return;
118 }
119
120 // First delete the directory and files in case this is a repeat call
121 std::filesystem::remove_all( lfr.testPath );
122
123 flatlogs::timespecX ts1( 1732170780, 1 );
124
125 mx::error_t rv = lfr.test_createFile( ts1 );
126
127 REQUIRE( rv == mx::error_t::noerror );
128 REQUIRE( std::filesystem::exists( lfr.testPath ) );
129 REQUIRE( std::filesystem::exists( lfr.testPath + "/2024_11_21/" ) );
130 REQUIRE( std::filesystem::exists( lfr.testPath + "/2024_11_21/" + lfr.logName() + "_20241121063300000000001." +
131 lfr.logExt() ) );
132
133 flatlogs::timespecX ts2( 1763706780, 50 );
134
135 rv = lfr.test_createFile( ts2 );
136
137 REQUIRE( rv == mx::error_t::noerror );
138 REQUIRE( std::filesystem::exists( lfr.testPath ) );
139 REQUIRE( std::filesystem::exists( lfr.testPath + "/2025_11_21/" ) );
140 REQUIRE( std::filesystem::exists( lfr.testPath + "/2025_11_21/" + lfr.logName() + "_20251121063300000000050." +
141 lfr.logExt() ) );
142 }
143
144 SECTION( "logPath without permissions" )
145 {
146 // check that this path doesn't already exist
147 if( std::filesystem::exists( "/lfrtest" ) )
148 {
149 std::cerr << "\nTESTING-ERROR: path /lsfrtest exists so permission test will be invalid. Can't go on\n";
150 std::cerr << __FILE__ << ' ' << __LINE__ << "\n\n";
151 REQUIRE( false );
152 return;
153 }
154
155 logFileRawTest lfr( "/lfrtest/" ); // not just root as a just in case
156
157 flatlogs::timespecX ts1( 1732170780, 1 );
158
159 mx::error_t errc = lfr.test_createFile( ts1 );
160
161
162 REQUIRE( errc != mx::error_t::noerror );
163 }
164
165 SECTION( "2nd timestamp is the same as the first, file already exists" )
166 {
167 logFileRawTest lfr;
168
169 // safety check to make sure we don't delete all of /tmp
170 if( lfr.testPath == "/tmp" )
171 {
172 std::cerr << "\nTESTING-ERROR: testPath is just /tmp, so logName is null. Can't go on\n";
173 std::cerr << __FILE__ << ' ' << __LINE__ << "\n\n";
174 REQUIRE( false );
175 return;
176 }
177
178 // First delete the directory and files in case this is a repeat call
179 std::filesystem::remove_all( lfr.testPath );
180
181 flatlogs::timespecX ts1( 1732170780, 1 );
182
183 mx::error_t rv = lfr.test_createFile( ts1 );
184
185 REQUIRE( rv == mx::error_t::noerror );
186 REQUIRE( std::filesystem::exists( lfr.testPath ) );
187 REQUIRE( std::filesystem::exists( lfr.testPath + "/2024_11_21/" ) );
188 REQUIRE( std::filesystem::exists( lfr.testPath + "/2024_11_21/" + lfr.logName() + "_20241121063300000000001." +
189 lfr.logExt() ) );
190
191 flatlogs::timespecX ts2( 1732170780, 1 );
192
193 rv = lfr.test_createFile( ts2 );
194
195 REQUIRE( rv == mx::error_t::eexist );
196 }
197}
198
200{
201 /// The event code
203
204 /// The default level
206
207 typedef std::string messageT;
208
209 /// The message string
210 static const char *msg()
211 {
212 return "LOOP CLOSED";
213 }
214
216 {
217 return msg.size();
218 }
219
220 static int format( void *msgBuffer, const messageT &msg )
221 {
222 memcpy( msgBuffer, msg.data(), msg.size() );
223 return 0;
224 }
225};
226
227/// Writing to a log file
228/**
229 * \ingroup logFileRaw_unit_test
230 */
231TEST_CASE( "Writing to a log file", "[libMagAOX::logger::logFileRaw]" )
232{
233 // clang-format off
234 #ifdef XWCTEST_DOXYGEN_REF_PROTECTED
235 logFileRaw lfr;
236 flatlogs::timespecX ts1( 1732170780, 1 );
237 lfr.createFile( ts1 );
238 flatlogs::bufferPtrT logbuff;
239 lfr.writeLog( logbuff );
240 lfr.logName();
241 lfr.logExt();
242 lfr.close()
243 lfr.m_logPath;
244 lfr.m_logName;
245 #endif
246 // clang-format on
247
248 SECTION( "Write to existing log" )
249 {
250 logFileRawTest lfr;
251
252 // safety check to make sure we don't delete all of /tmp
253 if( lfr.testPath == "/tmp" )
254 {
255 std::cerr << "\nTESTING-ERROR: testPath is just /tmp, so logName is null. Can't go on\n";
256 std::cerr << __FILE__ << ' ' << __LINE__ << "\n\n";
257 REQUIRE( false );
258 return;
259 }
260
261 // First delete the directory and files in case this is a repeat call
262 std::filesystem::remove_all( lfr.testPath );
263
264 flatlogs::timespecX ts1( 1732170780, 1 );
265
266 mx::error_t rv = lfr.test_createFile( ts1 );
267
268 REQUIRE( rv == mx::error_t::noerror );
269 REQUIRE( std::filesystem::exists( lfr.testPath ) );
270 REQUIRE( std::filesystem::exists( lfr.testPath + "/2024_11_21/" ) );
271
272 std::string fullPath = lfr.testPath + "/2024_11_21/" + lfr.logName() + "_20241121063300000000001.";
273 fullPath += lfr.logExt();
274
275 REQUIRE( std::filesystem::exists( fullPath ) );
276
277 flatlogs::bufferPtrT logbuff;
278 flatlogs::timespecX ts2( 1732170780, 2 );
279 std::string msg( 256, 't' );
280
281 flatlogs::logHeader::createLog<dummyLog>( logbuff, ts2, msg, flatlogs::logPrio::LOG_NOTICE );
282
283 rv = lfr.writeLog( logbuff );
284 REQUIRE( rv == mx::error_t::noerror );
285
286 REQUIRE( lfr.close() == mx::error_t::noerror );
287
288 std::uintmax_t fsz = std::filesystem::file_size( fullPath );
289
290 REQUIRE( fsz == 1 * ( 256 + 14 ) );
291 }
292
293 SECTION( "Write to log that doesn't exist yet" )
294 {
295 logFileRawTest lfr;
296
297 // safety check to make sure we don't delete all of /tmp
298 if( lfr.testPath == "/tmp" )
299 {
300 std::cerr << "\nTESTING-ERROR: testPath is just /tmp, so logName is null. Can't go on\n";
301 std::cerr << __FILE__ << ' ' << __LINE__ << "\n\n";
302 REQUIRE( false );
303 return;
304 }
305
306 // First delete the directory and files in case this is a repeat call
307 std::filesystem::remove_all( lfr.testPath );
308
309 flatlogs::bufferPtrT logbuff;
310 flatlogs::timespecX ts2( 1732170780, 2 );
311 std::string msg( 256, 't' );
312
313 flatlogs::logHeader::createLog<dummyLog>( logbuff, ts2, msg, flatlogs::logPrio::LOG_NOTICE );
314
315 mx::error_t rv = lfr.writeLog( logbuff );
316 REQUIRE( rv == mx::error_t::noerror );
317
318 REQUIRE( std::filesystem::exists( lfr.testPath ) );
319 REQUIRE( std::filesystem::exists( lfr.testPath + "/2024_11_21/" ) );
320
321 std::string fullPath = lfr.testPath + "/2024_11_21/" + lfr.logName() + "_20241121063300000000002.";
322 fullPath += lfr.logExt();
323
324 REQUIRE( std::filesystem::exists( fullPath ) );
325
326 REQUIRE( lfr.close() == mx::error_t::noerror );
327
328 std::uintmax_t fsz = std::filesystem::file_size( fullPath );
329
330 REQUIRE( fsz == 1 * ( 256 + 14 ) );
331 }
332
333 SECTION( "Write to log twice, does not exceed size" )
334 {
335 logFileRawTest lfr;
336
337 // safety check to make sure we don't delete all of /tmp
338 if( lfr.testPath == "/tmp" )
339 {
340 std::cerr << "\nTESTING-ERROR: testPath is just /tmp, so logName is null. Can't go on\n";
341 std::cerr << __FILE__ << ' ' << __LINE__ << "\n\n";
342 REQUIRE( false );
343 return;
344 }
345
346 // First delete the directory and files in case this is a repeat call
347 std::filesystem::remove_all( lfr.testPath );
348
349 flatlogs::bufferPtrT logbuff;
350 flatlogs::timespecX ts2( 1732170780, 2 );
351 std::string msg( 256, 't' );
352
353 flatlogs::logHeader::createLog<dummyLog>( logbuff, ts2, msg, flatlogs::logPrio::LOG_NOTICE );
354
355 mx::error_t rv = lfr.writeLog( logbuff );
356 REQUIRE( rv == mx::error_t::noerror );
357
358 REQUIRE( std::filesystem::exists( lfr.testPath ) );
359 REQUIRE( std::filesystem::exists( lfr.testPath + "/2024_11_21/" ) );
360
361 std::string fullPath = lfr.testPath + "/2024_11_21/" + lfr.logName() + "_20241121063300000000002.";
362 fullPath += lfr.logExt();
363
364 REQUIRE( std::filesystem::exists( fullPath ) );
365
366 flatlogs::timespecX ts3( 1732170780, 50 );
367 flatlogs::bufferPtrT logbuff3;
368 flatlogs::logHeader::createLog<dummyLog>( logbuff3, ts3, msg, flatlogs::logPrio::LOG_NOTICE );
369
370 rv = lfr.writeLog( logbuff3 );
371 REQUIRE( rv == mx::error_t::noerror );
372
373 // New file not created
374 std::string fullPath2 = lfr.testPath + "/2024_11_21/" + lfr.logName() + "_20241121063300000000050.";
375 fullPath2 += lfr.logExt();
376
377 REQUIRE( !std::filesystem::exists( fullPath2 ) );
378
379 lfr.close();
380
381 std::uintmax_t fsz = std::filesystem::file_size( fullPath );
382
383 REQUIRE( fsz == 2 * ( 256 + 14 ) ); // has two logs in it
384 }
385
386 SECTION( "Write to log twice, does exceed size" )
387 {
388 logFileRawTest lfr;
389 lfr.maxLogSize( 256 );
390
391 // safety check to make sure we don't delete all of /tmp
392 if( lfr.testPath == "/tmp" )
393 {
394 std::cerr << "\nTESTING-ERROR: testPath is just /tmp, so logName is null. Can't go on\n";
395 std::cerr << __FILE__ << ' ' << __LINE__ << "\n\n";
396 REQUIRE( false );
397 return;
398 }
399
400 // First delete the directory and files in case this is a repeat call
401 std::filesystem::remove_all( lfr.testPath );
402
403 flatlogs::bufferPtrT logbuff;
404 flatlogs::timespecX ts( 1732170780, 2 );
405 std::string msg( 256, 't' );
406
407 flatlogs::logHeader::createLog<dummyLog>( logbuff, ts, msg, flatlogs::logPrio::LOG_NOTICE );
408
409 mx::error_t rv = lfr.writeLog( logbuff );
410 REQUIRE( rv == mx::error_t::noerror );
411
412 REQUIRE( std::filesystem::exists( lfr.testPath ) );
413 REQUIRE( std::filesystem::exists( lfr.testPath + "/2024_11_21/" ) );
414
415 std::string fullPath = lfr.testPath + "/2024_11_21/" + lfr.logName() + "_20241121063300000000002.";
416 fullPath += lfr.logExt();
417
418 REQUIRE( std::filesystem::exists( fullPath ) );
419
420 flatlogs::timespecX ts2( 1732170780, 50 );
421 flatlogs::bufferPtrT logbuff2;
422 flatlogs::logHeader::createLog<dummyLog>( logbuff2, ts2, msg, flatlogs::logPrio::LOG_NOTICE );
423
424 rv = lfr.writeLog( logbuff2 );
425 REQUIRE( rv == mx::error_t::noerror );
426
427 // New file created
428 std::string fullPath2 = lfr.testPath + "/2024_11_21/" + lfr.logName() + "_20241121063300000000050.";
429 fullPath2 += lfr.logExt();
430
431 REQUIRE( std::filesystem::exists( fullPath2 ) );
432
433 // Test this before closing, as this will probably only pass if the previous file was closed
434 std::uintmax_t fsz = std::filesystem::file_size( fullPath );
435
436 REQUIRE( fsz == 1 * ( 256 + 14 ) );
437
438 lfr.close();
439
440 fsz = std::filesystem::file_size( fullPath2 );
441
442 REQUIRE( fsz == 1 * ( 256 + 14 ) );
443 }
444}
445
446} // namespace logFileRawTest
447} // namespace loggerTest
448} // namespace libXWCTest
A class to manage raw binary log files.
mx::error_t logExt(const std::string &newExt)
Set the log extension.
mx::error_t writeLog(flatlogs::bufferPtrT &data)
Write a log entry to the file.
mx::error_t logPath(const std::string &newPath)
Set the path.
mx::error_t maxLogSize(size_t newMaxFileSize)
Set the maximum file size.
mx::error_t logName(const std::string &newName)
Set the log name.
std::string m_logName
The base name for the log files.
std::string m_logPath
The base path for the log files.
mx::error_t close()
Close the file pointer.
mx::error_t createFile(flatlogs::timespecX &ts)
Create a new file.
mx::error_t test_createFile(flatlogs::timespecX &ts)
#define MAGAOX_default_logExt
The extension for MagAO-X binary log files.
Definition defaults.hpp:22
#define MAGAOX_default_max_logSize
The default maximum log file size.
Definition defaults.hpp:40
uint16_t eventCodeT
The type of an event code (16-bit unsigned int).
Definition logDefs.hpp:40
msgLen2T msgLenT
The type used to refer to the message length, regardless of length.
Definition logDefs.hpp:69
int8_t logPrioT
The type of the log priority code.
Definition logDefs.hpp:21
TEST_CASE("Construction of logFileRaw", "[libMagAOX::logger::logFileRaw]")
Construction of logFileRaw.
std::shared_ptr< char > bufferPtrT
The log entry buffer smart pointer.
Definition logHeader.hpp:58
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
Namespace for all libXWC tests.
Definition MagAOXApp.hpp:49
A fixed-width timespec structure.
Definition timespecX.hpp:35
static flatlogs::msgLenT length(const messageT &msg)
static const flatlogs::logPrioT defaultLevel
The default level.
static const flatlogs::eventCodeT eventCode
The event code.
static const char * msg()
The message string.
static int format(void *msgBuffer, const messageT &msg)