API
 
Loading...
Searching...
No Matches
MagAOXApp_test.cpp
Go to the documentation of this file.
1// #define CATCH_CONFIG_MAIN
2#include "../../../tests/catch2/catch.hpp"
3
4#include <filesystem>
5
6#include <mx/sys/timeUtils.hpp>
7
8#include "../MagAOXApp.hpp"
9#include "MagAOXApp_test.hpp"
10
11#undef app_MagAOXApp_hpp
12#undef app_tests_MagAOXApp_test_hpp
13#define XWCTEST_NAMESPACE XWCTEST_MAGAOXAPP_PID_LOCKED_ns
14#define XWCTEST_MAGAOXAPP_PID_LOCKED
15#include "../MagAOXApp.hpp"
16#include "MagAOXApp_test.hpp"
17#undef XWCTEST_NAMESPACE
18#undef XWCTEST_MAGAOXAPP_PID_LOCKED
19
20#undef app_MagAOXApp_hpp
21#undef app_tests_MagAOXApp_test_hpp
22#define XWCTEST_NAMESPACE XWCTEST_MAGAOXAPP_PID_WRITE_FAIL_ns
23#define XWCTEST_MAGAOXAPP_PID_WRITE_FAIL
24#include "../MagAOXApp.hpp"
25#include "MagAOXApp_test.hpp"
26#undef XWCTEST_NAMESPACE
27#undef XWCTEST_MAGAOXAPP_PID_WRITE_FAIL
28
29namespace libXWCTest
30{
31namespace appTest
32{
33
34/** \defgroup MagAOXApp_unit_test stdFileName Unit Tests
35 * \ingroup app_unit_test
36 */
37
38/// Namespace for XWC::app::MagAOXApp tests
39/** \ingroup MagAOXApp_unit_test
40 *
41 */
42namespace MagAOXAppTest
43{
44
45/// MagAOXApp 2nd instance
46/**
47 * \ingroup MagAOXApp_unit_test
48 */
49TEST_CASE( "MagAOXApp 2nd instance", "[app::MagAOXApp]" )
50{
51
52 SECTION( "test 2nd app" )
53 {
54 bool caught = false;
55
56 MagAOXApp_test app1;
57
58 try
59 {
60 MagAOXApp_test app2;
61 }
62 catch( const std::logic_error &e )
63 {
64 caught = true;
65 }
66
67 REQUIRE( caught == true );
68 }
69}
70
71/// MagAOXApp INDI NewProperty
72/**
73 * \ingroup MagAOXApp_unit_test
74 */
75SCENARIO( "MagAOXApp INDI NewProperty", "[app::MagAOXApp]" )
76{
77 GIVEN( "a new property request" )
78 {
79 WHEN( "a wrong device name" )
80 {
82
83 app.setConfigName( "test" );
84
85 REQUIRE( app.configName() == "test" );
86
87 pcf::IndiProperty prop;
88 app.registerIndiPropertyNew( prop,
89 "nprop",
90 pcf::IndiProperty::Number,
91 pcf::IndiProperty::ReadWrite,
92 pcf::IndiProperty::Idle,
93 callback );
94
95 pcf::IndiProperty nprop;
96
97 // First test the right device name
98 nprop.setDevice( "test" );
99 nprop.setName( "nprop" );
100
101 app.handleNewProperty( nprop );
102
103 REQUIRE( app.called_back == 1 );
104
105 app.called_back = 0;
106
107 // Now test the wrong device name
108 nprop.setDevice( "wrong" );
109
110 app.handleNewProperty( nprop );
111
112 REQUIRE( app.called_back == 0 );
113 }
114 }
115}
116
117/// MagAOXApp_unit_test
118/**
119 * \ingroup MagAOXApp_unit_test
120 */
121TEST_CASE( "Setting defaults", "[app::MagAOXApp]" )
122{
123 SECTION( "using default paths, configname is invoked name" )
124 {
125 std::vector<std::string> argvstr( { "./execname" } );
126
127 std::vector<const char *> argv( argvstr.size() + 1, NULL );
128 for( size_t index = 0; index < argvstr.size(); ++index )
129 {
130 argv[index] = argvstr[index].c_str();
131 }
132
133 MagAOXApp_test app;
134
135 app.invokedName() = argv[0];
136 REQUIRE( app.doHelp() == false );
137 app.setDefaults( argv.size() - 1, const_cast<char **>( argv.data() ) );
138 REQUIRE( app.doHelp() == true );
139
140 app.basePath(); // make lcov records this call
141 REQUIRE( app.basePath() == MAGAOX_path );
142 app.configDir(); // make lcov records this call
143 REQUIRE( app.configDir() == app.basePath() + '/' + MAGAOX_configRelPath );
144 REQUIRE( app.configPathGlobal() == app.configDir() + "/magaox.conf" );
145 app.calibDir(); // make lcov records this call
146 REQUIRE( app.calibDir() == app.basePath() + '/' + MAGAOX_calibRelPath );
147 REQUIRE( app.m_log.logPath() == app.basePath() + '/' + MAGAOX_logRelPath );
148 app.sysPath(); // make lcov records this call
149 REQUIRE( app.sysPath() == app.basePath() + '/' + MAGAOX_sysRelPath );
150 app.secretsPath(); // make lcov records this call
151 REQUIRE( app.secretsPath() == app.basePath() + '/' + MAGAOX_secretsRelPath );
152 app.cpusetPath(); // make lcov records this call
153 REQUIRE( app.cpusetPath() == MAGAOX_cpusetPath );
154 app.configBase(); // make lcov records this call
155 REQUIRE( app.configBase() == "" );
156 REQUIRE( app.configPathUser() == "" );
157 REQUIRE( app.configName() == "execname" );
158 REQUIRE( app.configPathLocal() == app.configDir() + "/execname.conf" );
159
160 REQUIRE( app.doHelp() == true );
161 }
162
163 SECTION( "using default paths, with config-ed name" )
164 {
165 std::vector<std::string> argvstr( { "./execname", "-n", "testapp" } );
166
167 std::vector<const char *> argv( argvstr.size() + 1, NULL );
168 for( size_t index = 0; index < argvstr.size(); ++index )
169 {
170 argv[index] = argvstr[index].c_str();
171 }
172
173 MagAOXApp_test app;
174 app.invokedName() = argv[0];
175
176 app.setDefaults( argv.size() - 1, const_cast<char **>( argv.data() ) );
177
178 REQUIRE( app.basePath() == MAGAOX_path );
179 REQUIRE( app.configDir() == app.basePath() + '/' + MAGAOX_configRelPath );
180 REQUIRE( app.configPathGlobal() == app.configDir() + "/magaox.conf" );
181 REQUIRE( app.calibDir() == app.basePath() + '/' + MAGAOX_calibRelPath );
182 REQUIRE( app.m_log.logPath() == app.basePath() + '/' + MAGAOX_logRelPath );
183
184 REQUIRE( app.sysPath() == app.basePath() + '/' + MAGAOX_sysRelPath );
185 REQUIRE( app.secretsPath() == app.basePath() + '/' + MAGAOX_secretsRelPath );
186 REQUIRE( app.cpusetPath() == MAGAOX_cpusetPath );
187 REQUIRE( app.configBase() == "" );
188 REQUIRE( app.configPathUser() == "" );
189 REQUIRE( app.configName() == "testapp" );
190 REQUIRE( app.configPathLocal() == app.configDir() + "/testapp.conf" );
191 REQUIRE( app.doHelp() == false );
192 }
193
194 // Something goes wrong here, third time is the charm.
195 // Hangs on config.parseCommandLine
196 SECTION( "using environment paths, with config-ed name" )
197 {
198 std::vector<const char *> argv;
199 std::vector<std::string> argvstr( { "./execname", "--name", "testapp2" } );
200
201 argv.resize( argvstr.size() + 1, NULL );
202 for( size_t index = 0; index < argvstr.size(); ++index )
203 {
204 argv[index] = argvstr[index].c_str();
205 }
206
207 char ppath[1024];
208 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
209 putenv( ppath );
210
211 char cpath[1024];
212 snprintf( cpath, sizeof( cpath ), "%s=config2", MAGAOX_env_config );
213 putenv( cpath );
214
215 char cbpath[1024];
216 snprintf( cbpath, sizeof( cbpath ), "%s=calib2", MAGAOX_env_calib );
217 putenv( cbpath );
218
219 char lpath[1024];
220 snprintf( lpath, sizeof( lpath ), "%s=logs2", MAGAOX_env_log );
221 putenv( lpath );
222
223 char syspath[1024];
224 snprintf( syspath, sizeof( syspath ), "%s=sys2", MAGAOX_env_sys );
225 putenv( syspath );
226
227 char secretspath[1024];
228 snprintf( secretspath, sizeof( secretspath ), "%s=secrets2", MAGAOX_env_secrets );
229 putenv( secretspath );
230
231 char cpupath[1024];
232 snprintf( cpupath, sizeof( cpupath ), "%s=/tmp/MagAOX/cpuset", MAGAOX_env_cpuset );
233 putenv( cpupath );
234
235 MagAOXApp_test app;
236
237 app.invokedName() = argv[0];
238 app.setConfigBase( "cbase" );
239
240 app.setDefaults( argv.size() - 1, const_cast<char **>( argv.data() ) );
241
242 REQUIRE( app.basePath() == "/tmp/MagAOXApp_test" );
243 REQUIRE( app.configDir() == app.basePath() + '/' + "config2" );
244 REQUIRE( app.configPathGlobal() == app.configDir() + "/magaox.conf" );
245 REQUIRE( app.calibDir() == app.basePath() + '/' + "calib2" );
246 REQUIRE( app.m_log.logPath() == app.basePath() + '/' + "logs2" );
247 REQUIRE( app.sysPath() == app.basePath() + '/' + "sys2" );
248 REQUIRE( app.secretsPath() == app.basePath() + '/' + "secrets2" );
249 REQUIRE( app.cpusetPath() == "/tmp/MagAOX/cpuset" );
250 REQUIRE( app.configBase() == "cbase" );
251 REQUIRE( app.configPathUser() == app.configDir() + "/cbase.conf" );
252 REQUIRE( app.configName() == "testapp2" );
253 REQUIRE( app.configPathLocal() == app.configDir() + "/testapp2.conf" );
254 REQUIRE( app.doHelp() == false );
255 }
256}
257
258/// Configuring MagAOXApp
259/**
260 * \ingroup MagAOXApp_unit_test
261 */
262TEST_CASE( "Configuring MagAOXApp", "[app::MagAOXApp]" )
263{
264 SECTION( "setup basic config" )
265 {
266 MagAOXApp_test app;
267 app.setPowerMgtEnabled( true );
268
269 app.setupBasicConfig();
270
271 REQUIRE( app.shutdown() == false );
272 }
273
274 SECTION( "load basic config w all defaults w/out pwr management" )
275 {
276 MagAOXApp_test app;
277 app.setPowerMgtEnabled( false );
278
279 app.setupBasicConfig();
280
281 app.loadBasicConfig();
282
283 app.checkConfig();
284
285 REQUIRE( app.stateAlert() == false );
286 REQUIRE( app.gitAlert() == false );
287 REQUIRE( app.shutdown() == false );
288 }
289
290 SECTION( "load basic config w all defaults w/out pwr management, setting state and clearing alerts" )
291 {
292 std::vector<const char *> argv;
293 std::vector<std::string> argvstr( { "./execname", "--name", "testapp" } );
294
295 argv.resize( argvstr.size() + 1, NULL );
296 for( size_t index = 0; index < argvstr.size(); ++index )
297 {
298 argv[index] = argvstr[index].c_str();
299 }
300
301 MagAOXApp_test app( true );
302 app.setPowerMgtEnabled( false );
303
304 app.setupBasicConfig();
305
306 app.setDefaults( argv.size() - 1, const_cast<char **>( argv.data() ) );
307
308 app.loadBasicConfig();
309
310 app.checkConfig();
311
312 REQUIRE( app.stateAlert() == true );
313 REQUIRE( app.gitAlert() == true );
314 REQUIRE( app.shutdown() == false );
315
316 app.doFSMClearAlert();
317 REQUIRE( app.stateAlert() == false );
318 REQUIRE( app.gitAlert() == true );
319 REQUIRE( app.shutdown() == false );
320
321 app.doFSMClearAlert(); // calls an immediate return of clearFSMAlert
322
323 // Now test each path out of clearFSMAlert
325 REQUIRE( app.state() == MagAOX::app::stateCodes::READY );
326
327 REQUIRE( app.stateLogged() == 0 );
328 REQUIRE( app.stateLogged() == 1 );
329
330 app.setAlert();
331 REQUIRE( app.stateAlert() == true );
332
333 app.doFSMClearAlert();
334 REQUIRE( app.stateAlert() == false );
335
338
339 app.setAlert();
340 REQUIRE( app.stateAlert() == true );
341
342 app.doFSMClearAlert();
343 REQUIRE( app.stateAlert() == false );
344
347
348 app.setAlert();
349 REQUIRE( app.stateAlert() == true );
350
351 app.doFSMClearAlert();
352 REQUIRE( app.stateAlert() == false );
353
356
357 app.setAlert();
358 REQUIRE( app.stateAlert() == true );
359
360 app.doFSMClearAlert();
361 REQUIRE( app.stateAlert() == false );
362
365
366 app.setAlert();
367 REQUIRE( app.stateAlert() == true );
368
369 app.doFSMClearAlert();
370 REQUIRE( app.stateAlert() == false );
371
374
375 app.setAlert();
376 REQUIRE( app.stateAlert() == true );
377
378 app.doFSMClearAlert();
379 REQUIRE( app.stateAlert() == false );
380 }
381
382 SECTION( "load basic config w all defaults w unconfigured pwr management" )
383 {
384 MagAOXApp_test app;
385 app.setPowerMgtEnabled( true );
386
387 app.setupBasicConfig();
388
389 app.loadBasicConfig();
390
391 REQUIRE( app.shutdown() == true );
392
393 app.checkConfig();
394
395 REQUIRE( app.stateAlert() == false );
396 REQUIRE( app.gitAlert() == false );
397 REQUIRE( app.shutdown() == true );
398 }
399
400 SECTION( "load a full config" )
401 {
402 std::vector<const char *> argv;
403 std::vector<std::string> argvstr( { "./execname", "-n", "testapp", "--config.validate" } );
404
405 argv.resize( argvstr.size() + 1, NULL );
406 for( size_t index = 0; index < argvstr.size(); ++index )
407 {
408 argv[index] = argvstr[index].c_str();
409 }
410
411 char ppath[1024];
412 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
413 putenv( ppath );
414
415 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/config" );
416
417 std::ofstream fout;
418 fout.open( "/tmp/MagAOXApp_test/config/magaox.conf" );
419 fout.close();
420
421 mx::app::writeConfigFile( "/tmp/MagAOXApp_test/config/testapp.conf",
422 { "", "power", "power", "power", "power", "power" },
423 { "loopPause", "device", "channel", "element", "targetElement", "powerOnWait" },
424 { "2500", "pdu9", "thisch", "thisel", "thistgtel", "500000" } );
425
426 MagAOXApp_test app( true );
427 app.setPowerMgtEnabled( true );
428
429 app.setup( argv.size() - 1, const_cast<char **>( argv.data() ) );
430
431 REQUIRE( app.stateAlert() == true ); // due to git
432 REQUIRE( app.configOnly() == true );
433 REQUIRE( app.loopPause() == 2500 );
434 REQUIRE( app.powerDevice() == "pdu9" );
435 REQUIRE( app.powerChannel() == "thisch" );
436 REQUIRE( app.powerElement() == "thisel" );
437 REQUIRE( app.powerTargetElement() == "thistgtel" );
438 REQUIRE( app.powerOnWait() == 0 );
439
440 REQUIRE( app.shutdown() == false );
441 }
442
443 SECTION( "load a full config w unknown config in file, do help" )
444 {
445 std::vector<const char *> argv;
446 std::vector<std::string> argvstr( { "./execname", "-n", "testapp" } );
447
448 argv.resize( argvstr.size() + 1, NULL );
449 for( size_t index = 0; index < argvstr.size(); ++index )
450 {
451 argv[index] = argvstr[index].c_str();
452 }
453
454 char ppath[1024];
455 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
456 putenv( ppath );
457
458 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/config" );
459
460 std::ofstream fout;
461 fout.open( "/tmp/MagAOXApp_test/config/magaox.conf" );
462 fout.close();
463
464 // this adds unknown=value
465 mx::app::writeConfigFile(
466 "/tmp/MagAOXApp_test/config/testapp.conf",
467 { "", "power", "power", "power", "power", "power", "" },
468 { "loopPause", "device", "channel", "element", "targetElement", "powerOnWait", "unknown" },
469 { "2500", "pdu9", "thisch", "thisel", "thistgtel", "500", "value" } );
470
471 MagAOXApp_test app( false );
472 app.setPowerMgtEnabled( true );
473
474 app.setup( argv.size() - 1, const_cast<char **>( argv.data() ) );
475
476 REQUIRE( app.stateAlert() == false );
477 REQUIRE( app.configOnly() == false );
478 REQUIRE( app.loopPause() == 2500 );
479 REQUIRE( app.powerDevice() == "pdu9" );
480 REQUIRE( app.powerChannel() == "thisch" );
481 REQUIRE( app.powerElement() == "thisel" );
482 REQUIRE( app.powerTargetElement() == "thistgtel" );
483 REQUIRE( app.powerOnWait() == 500 );
484
485 REQUIRE( app.doHelp() == true );
486 REQUIRE( app.shutdown() == true );
487 }
488
489 SECTION( "load a full config w unknown config in file, validate" )
490 {
491 std::vector<const char *> argv;
492 std::vector<std::string> argvstr( { "./execname", "-n", "testapp", "--config.validate" } );
493
494 argv.resize( argvstr.size() + 1, NULL );
495 for( size_t index = 0; index < argvstr.size(); ++index )
496 {
497 argv[index] = argvstr[index].c_str();
498 }
499
500 char ppath[1024];
501 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
502 putenv( ppath );
503
504 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/config" );
505
506 std::ofstream fout;
507 fout.open( "/tmp/MagAOXApp_test/config/magaox.conf" );
508 fout.close();
509
510 // this adds unknown=value
511 mx::app::writeConfigFile(
512 "/tmp/MagAOXApp_test/config/testapp.conf",
513 { "", "power", "power", "power", "power", "power", "" },
514 { "loopPause", "device", "channel", "element", "targetElement", "powerOnWait", "unknown" },
515 { "2500", "pdu9", "thisch", "thisel", "thistgtel", "500000", "value" } );
516
517 MagAOXApp_test app( true );
518 app.setPowerMgtEnabled( true );
519
520 app.setup( argv.size() - 1, const_cast<char **>( argv.data() ) );
521
522 REQUIRE( app.stateAlert() == true ); // due to git
523 REQUIRE( app.configOnly() == true );
524 REQUIRE( app.loopPause() == 2500 );
525 REQUIRE( app.powerDevice() == "pdu9" );
526 REQUIRE( app.powerChannel() == "thisch" );
527 REQUIRE( app.powerElement() == "thisel" );
528 REQUIRE( app.powerTargetElement() == "thistgtel" );
529 REQUIRE( app.powerOnWait() == 0 );
530
531 REQUIRE( app.doHelp() == false );
532 REQUIRE( app.shutdown() == true );
533 }
534
535 SECTION( "load a full config w non-option clopt" )
536 {
537 std::vector<const char *> argv;
538 std::vector<std::string> argvstr( { "./execname", "-n", "testapp", "straylight" } );
539
540 argv.resize( argvstr.size() + 1, NULL );
541 for( size_t index = 0; index < argvstr.size(); ++index )
542 {
543 argv[index] = argvstr[index].c_str();
544 }
545
546 char ppath[1024];
547 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
548 putenv( ppath );
549
550 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/config" );
551
552 std::ofstream fout;
553 fout.open( "/tmp/MagAOXApp_test/config/magaox.conf" );
554 fout.close();
555
556 mx::app::writeConfigFile( "/tmp/MagAOXApp_test/config/testapp.conf",
557 { "", "power", "power", "power", "power", "power" },
558 { "loopPause", "device", "channel", "element", "targetElement", "powerOnWait" },
559 { "2500", "pdu9", "thisch", "thisel", "thistgtel", "500000" } );
560
561 MagAOXApp_test app( false );
562 app.setPowerMgtEnabled( true );
563
564 app.setup( argv.size() - 1, const_cast<char **>( argv.data() ) );
565
566 REQUIRE( app.stateAlert() == false ); // due to git
567 REQUIRE( app.configOnly() == false );
568 REQUIRE( app.loopPause() == 2500 );
569 REQUIRE( app.powerDevice() == "pdu9" );
570 REQUIRE( app.powerChannel() == "thisch" );
571 REQUIRE( app.powerElement() == "thisel" );
572 REQUIRE( app.powerTargetElement() == "thistgtel" );
573 REQUIRE( app.powerOnWait() == 0 );
574
575 REQUIRE( app.doHelp() == true );
576 REQUIRE( app.shutdown() == true );
577 }
578
579 SECTION( "load a full config w no power mgt opts" )
580 {
581 std::vector<const char *> argv;
582 std::vector<std::string> argvstr( { "./execname", "-n", "testapp" } );
583
584 argv.resize( argvstr.size() + 1, NULL );
585 for( size_t index = 0; index < argvstr.size(); ++index )
586 {
587 argv[index] = argvstr[index].c_str();
588 }
589
590 char ppath[1024];
591 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
592 putenv( ppath );
593
594 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/config" );
595
596 std::ofstream fout;
597 fout.open( "/tmp/MagAOXApp_test/config/magaox.conf" );
598 fout.close();
599
600 mx::app::writeConfigFile( "/tmp/MagAOXApp_test/config/testapp.conf", { "" }, { "loopPause" }, { "2500" } );
601
602 MagAOXApp_test app( false );
603 app.setPowerMgtEnabled( true );
604
605 app.setup( argv.size() - 1, const_cast<char **>( argv.data() ) );
606
607 REQUIRE( app.stateAlert() == false ); // due to git
608 REQUIRE( app.configOnly() == false );
609 REQUIRE( app.loopPause() == 2500 );
610 REQUIRE( app.powerDevice() == "" );
611 REQUIRE( app.powerChannel() == "" );
612 REQUIRE( app.powerElement() == "state" );
613 REQUIRE( app.powerTargetElement() == "target" );
614 REQUIRE( app.powerOnWait() == 0 );
615
616 REQUIRE( app.doHelp() == true );
617 REQUIRE( app.shutdown() == true );
618 }
619
620 SECTION( "load a full config w unused config options" )
621 {
622 std::vector<const char *> argv;
623 std::vector<std::string> argvstr( { "./execname", "-n", "testapp", "--config.validate" } );
624
625 argv.resize( argvstr.size() + 1, NULL );
626 for( size_t index = 0; index < argvstr.size(); ++index )
627 {
628 argv[index] = argvstr[index].c_str();
629 }
630
631 char ppath[1024];
632 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
633 putenv( ppath );
634
635 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/config" );
636
637 std::ofstream fout;
638 fout.open( "/tmp/MagAOXApp_test/config/magaox.conf" );
639 fout.close();
640
641 // this adds unknown=value
642 mx::app::writeConfigFile( "/tmp/MagAOXApp_test/config/testapp.conf",
643 { "", "power", "power", "power", "power", "power" },
644 { "loopPause", "device", "channel", "element", "targetElement", "powerOnWait" },
645 { "2500", "pdu9", "thisch", "thisel", "thistgtel", "500000" } );
646
647 MagAOXApp_test app( true );
648 app.setPowerMgtEnabled( true );
649
650 app.addUnusedConfig();
651
652 app.setup( argv.size() - 1, const_cast<char **>( argv.data() ) );
653
654 REQUIRE( app.stateAlert() == true ); // due to git
655 REQUIRE( app.configOnly() == true );
656 REQUIRE( app.loopPause() == 2500 );
657 REQUIRE( app.powerDevice() == "pdu9" );
658 REQUIRE( app.powerChannel() == "thisch" );
659 REQUIRE( app.powerElement() == "thisel" );
660 REQUIRE( app.powerTargetElement() == "thistgtel" );
661 REQUIRE( app.powerOnWait() == 0 );
662
663 REQUIRE( app.doHelp() == false );
664 REQUIRE( app.shutdown() == false );
665 }
666}
667
668/// PID Locking
669/**
670 * \ingroup MagAOXApp_unit_test
671 */
672TEST_CASE( "PID Locking", "[app::MagAOXApp]" )
673{
674 SECTION( "Basic PID Lock" )
675 {
676 std::vector<const char *> argv;
677 std::vector<std::string> argvstr( { "./execname", "-n", "testapp" } );
678
679 argv.resize( argvstr.size() + 1, NULL );
680 for( size_t index = 0; index < argvstr.size(); ++index )
681 {
682 argv[index] = argvstr[index].c_str();
683 }
684
685 char ppath[1024];
686 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
687 putenv( ppath );
688
689 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/sys/" );
690
691 // First delete the directory and files in case this is a repeat call
692 std::filesystem::remove_all( "/tmp/MagAOXApp_test/sys/testapp" );
693
694 MagAOXApp_test app;
695 app.invokedName() = argv[0];
696 app.setDefaults( argv.size() - 1, const_cast<char **>( argv.data() ) );
697
698 REQUIRE( !std::filesystem::exists( "/tmp/MagAOXApp_test/sys/testapp/pid" ) );
699
700 int rv = app.lockPID();
701 REQUIRE( rv == 0 );
702 REQUIRE( std::filesystem::exists( "/tmp/MagAOXApp_test/sys/testapp/pid" ) );
703
704 rv = app.unlockPID();
705 REQUIRE( rv == 0 );
706 REQUIRE( !std::filesystem::exists( "/tmp/MagAOXApp_test/sys/testapp/pid" ) );
707 }
708
709 SECTION( "PID Lock, app directory creation erryr" )
710 {
711 std::vector<const char *> argv;
712 std::vector<std::string> argvstr( { "./execname", "-n", "testapp" } );
713
714 argv.resize( argvstr.size() + 1, NULL );
715 for( size_t index = 0; index < argvstr.size(); ++index )
716 {
717 argv[index] = argvstr[index].c_str();
718 }
719
720 char ppath[1024];
721 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
722 putenv( ppath );
723
724 // First delete the directory and files in case this is a repeat call
725 std::filesystem::remove_all( "/tmp/MagAOXApp_test" );
726
727 MagAOXApp_test app;
728 app.invokedName() = argv[0];
729 app.setDefaults( argv.size() - 1, const_cast<char **>( argv.data() ) );
730
731 int rv = app.lockPID();
732 REQUIRE( rv == -1 );
733
734 rv = app.unlockPID();
735 REQUIRE( rv == -1 );
736 }
737
738 SECTION( "Stale lock" )
739 {
740 std::vector<const char *> argv;
741 std::vector<std::string> argvstr( { "./execname", "-n", "testapp" } );
742
743 argv.resize( argvstr.size() + 1, NULL );
744 for( size_t index = 0; index < argvstr.size(); ++index )
745 {
746 argv[index] = argvstr[index].c_str();
747 }
748
749 char ppath[1024];
750 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
751 putenv( ppath );
752
753 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/sys/testapp" );
754
755 std::ofstream fout;
756 fout.open( "/tmp/MagAOXApp_test/sys/testapp/pid" );
757 fout << 1;
758 fout.close();
759
760 MagAOXApp_test app;
761 app.invokedName() = argv[0];
762 app.setDefaults( argv.size() - 1, const_cast<char **>( argv.data() ) );
763
764 int rv = app.lockPID();
765 REQUIRE( rv == 0 );
766 REQUIRE( std::filesystem::exists( "/tmp/MagAOXApp_test/sys/testapp/pid" ) );
767
768 rv = app.unlockPID();
769 REQUIRE( rv == 0 );
770 REQUIRE( !std::filesystem::exists( "/tmp/MagAOXApp_test/sys/testapp/pid" ) );
771 }
772
773 SECTION( "already locked" )
774 {
775 std::vector<const char *> argv;
776 std::vector<std::string> argvstr( { "./execname", "-n", "testapp" } );
777
778 argv.resize( argvstr.size() + 1, NULL );
779 for( size_t index = 0; index < argvstr.size(); ++index )
780 {
781 argv[index] = argvstr[index].c_str();
782 }
783
784 char ppath[1024];
785 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
786 putenv( ppath );
787
788 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/sys/testapp" );
789
790 std::ofstream fout;
791 fout.open( "/tmp/MagAOXApp_test/sys/testapp/pid" );
792 fout << 1;
793 fout.close();
794
795 XWCTEST_MAGAOXAPP_PID_LOCKED_ns::MagAOXApp_test app;
796 app.invokedName() = argv[0];
797 app.setDefaults( argv.size() - 1, const_cast<char **>( argv.data() ) );
798
799 int rv = app.lockPID();
800 REQUIRE( rv == -1 );
801 }
802
803 SECTION( "write fails" )
804 {
805 std::vector<const char *> argv;
806 std::vector<std::string> argvstr( { "./execname", "-n", "testapp" } );
807
808 argv.resize( argvstr.size() + 1, NULL );
809 for( size_t index = 0; index < argvstr.size(); ++index )
810 {
811 argv[index] = argvstr[index].c_str();
812 }
813
814 char ppath[1024];
815 snprintf( ppath, sizeof( ppath ), "%s=/tmp/MagAOXApp_test", MAGAOX_env_path );
816 putenv( ppath );
817
818 mx::ioutils::createDirectories( "/tmp/MagAOXApp_test/sys/testapp" );
819
820 std::ofstream fout;
821 fout.open( "/tmp/MagAOXApp_test/sys/testapp/pid" );
822 fout << 1;
823 fout.close();
824
825 XWCTEST_MAGAOXAPP_PID_WRITE_FAIL_ns::MagAOXApp_test app;
826 app.invokedName() = argv[0];
827 app.setDefaults( argv.size() - 1, const_cast<char **>( argv.data() ) );
828
829 int rv = app.lockPID();
830 REQUIRE( rv == -1 );
831 }
832}
833
834/// MagAOXApp Power Management Logic Outside of Execute
835/**
836 * \ingroup MagAOXApp_unit_test
837 */
838TEST_CASE( "MagAOXApp Power Management Logic Outside of Execute", "[app::MagAOXApp]" )
839{
840 SECTION( "Power Management Not Configured" )
841 {
842 MagAOXApp_test app( true );
843 app.setPowerMgtEnabled( false );
844
845 REQUIRE( app.onPowerOff() == 0 );
846 REQUIRE( app.whilePowerOff() == 0 );
847 REQUIRE( app.powerOnWaitElapsed() == true );
848 REQUIRE( app.powerState() == 1 );
849 REQUIRE( app.powerStateTarget() == 1 );
850 }
851
852 SECTION( "Power Management Configured" )
853 {
854 MagAOXApp_test app( true );
855 app.setPowerMgtEnabled( true );
856 app.configurePowerManagement( "pdu", "test" );
857
858 REQUIRE( app.onPowerOff() == 0 );
859 REQUIRE( app.whilePowerOff() == 0 );
860 REQUIRE( app.powerOnWaitElapsed() == true );
861
862 // Comes up unknown
863 REQUIRE( app.powerState() == -1 );
864 REQUIRE( app.powerStateTarget() == -1 );
865
866 app.setPowerState( "Off", "Off" );
867 REQUIRE( app.powerState() == 0 );
868 REQUIRE( app.powerStateTarget() == 0 );
869
870 app.setPowerState( "Int", "Int" );
871 REQUIRE( app.powerState() == -1 );
872 REQUIRE( app.powerStateTarget() == -1 );
873
874 app.setPowerState( "Off", "On" );
875 REQUIRE( app.powerState() == 0 );
876 REQUIRE( app.powerStateTarget() == 1 );
877
878 app.configurePowerOnWait( 10, 0, 1e9 );
879 REQUIRE( app.loopPause() == 1e9 );
880
881 // 10 checks, then true on 11th
882 REQUIRE( app.powerOnWaitElapsed() == false );
883 REQUIRE( app.powerOnWaitElapsed() == false );
884 REQUIRE( app.powerOnWaitElapsed() == false );
885 REQUIRE( app.powerOnWaitElapsed() == false );
886 REQUIRE( app.powerOnWaitElapsed() == false );
887 REQUIRE( app.powerOnWaitElapsed() == false );
888 REQUIRE( app.powerOnWaitElapsed() == false );
889 REQUIRE( app.powerOnWaitElapsed() == false );
890 REQUIRE( app.powerOnWaitElapsed() == false );
891 REQUIRE( app.powerOnWaitElapsed() == false );
892 REQUIRE( app.powerOnWaitElapsed() == false );
893 REQUIRE( app.powerOnWaitElapsed() == true );
894
895 app.setPowerState( "On", "On" );
896 REQUIRE( app.powerState() == 1 );
897 REQUIRE( app.powerStateTarget() == 1 );
898
899 app.setPowerState( "On", "Off" );
900 REQUIRE( app.powerState() == 1 );
901 REQUIRE( app.powerStateTarget() == 0 );
902
903 app.setPowerState( "Off", "Off" );
904 REQUIRE( app.powerState() == 0 );
905 REQUIRE( app.powerStateTarget() == 0 );
906 }
907}
908
909/// INDI preperty creation utilities
910/**
911 * \ingroup MagAOXApp_unit_test
912 */
913TEST_CASE( "INDI preperty creation utilities", "[app::MagAOXApp]" )
914{
915 SECTION( "createStandardIndiText" )
916 {
917 MagAOXApp_test app;
918 app.setConfigName( "test" );
919
920 pcf::IndiProperty ip;
921
922 app.createStandardIndiText( ip, "tprop", "tlabel", "tgroup" );
923
924 REQUIRE( ip.getType() == pcf::IndiProperty::Text );
925 REQUIRE( ip.getDevice() == "test" );
926 REQUIRE( ip.getName() == "tprop" );
927 REQUIRE( ip.getPerm() == pcf::IndiProperty::ReadWrite );
928 REQUIRE( ip.getState() == pcf::IndiProperty::Idle );
929 REQUIRE( ip.find( "current" ) == true );
930 REQUIRE( ip.find( "target" ) == true );
931 REQUIRE( ip.getLabel() == "tlabel" );
932 REQUIRE( ip.getGroup() == "tgroup" );
933 }
934
935 SECTION( "createROIndiText" )
936 {
937 MagAOXApp_test app;
938 app.setConfigName( "test" );
939
940 pcf::IndiProperty ip;
941
942 app.createROIndiText( ip, "tprop", "tel", "tlabel", "tgroup", "ellabel" );
943
944 REQUIRE( ip.getType() == pcf::IndiProperty::Text );
945 REQUIRE( ip.getDevice() == "test" );
946 REQUIRE( ip.getName() == "tprop" );
947 REQUIRE( ip.getPerm() == pcf::IndiProperty::ReadOnly );
948 REQUIRE( ip.getState() == pcf::IndiProperty::Idle );
949 REQUIRE( ip.getLabel() == "tlabel" );
950 REQUIRE( ip.getGroup() == "tgroup" );
951
952 REQUIRE( ip.find( "tel" ) == true );
953 REQUIRE( ip["tel"].getLabel() == "ellabel" );
954 }
955
956 SECTION( "createStandardIndiNumber" )
957 {
958 MagAOXApp_test app;
959 app.setConfigName( "test" );
960
961 pcf::IndiProperty ip;
962
963 app.createStandardIndiNumber<double>( ip, "tprop", 0.001, 1, 0.002, "%0.23g", "tlabel", "tgroup" );
964
965 REQUIRE( ip.getType() == pcf::IndiProperty::Number );
966 REQUIRE( ip.getDevice() == "test" );
967 REQUIRE( ip.getName() == "tprop" );
968 REQUIRE( ip.getPerm() == pcf::IndiProperty::ReadWrite );
969 REQUIRE( ip.getState() == pcf::IndiProperty::Idle );
970
971 REQUIRE( ip.find( "current" ) == true );
972 REQUIRE( ip["current"].getMin() == "0.001" );
973 REQUIRE( ip["current"].getMax() == "1" );
974 REQUIRE( ip["current"].getStep() == "0.002" );
975 REQUIRE( ip["current"].getFormat() == "%0.23g" );
976
977 REQUIRE( ip.find( "target" ) == true );
978 REQUIRE( ip["target"].getMin() == "0.001" );
979 REQUIRE( ip["target"].getMax() == "1" );
980 REQUIRE( ip["target"].getStep() == "0.002" );
981 REQUIRE( ip["target"].getFormat() == "%0.23g" );
982
983 REQUIRE( ip.getLabel() == "tlabel" );
984 REQUIRE( ip.getGroup() == "tgroup" );
985 }
986
987 SECTION( "createROIndiNumber" )
988 {
989 MagAOXApp_test app;
990 app.setConfigName( "test" );
991
992 pcf::IndiProperty ip;
993
994 app.createROIndiNumber( ip, "tprop", "tlabel", "tgroup" );
995
996 REQUIRE( ip.getType() == pcf::IndiProperty::Number );
997 REQUIRE( ip.getDevice() == "test" );
998 REQUIRE( ip.getName() == "tprop" );
999 REQUIRE( ip.getPerm() == pcf::IndiProperty::ReadOnly );
1000 REQUIRE( ip.getState() == pcf::IndiProperty::Idle );
1001 REQUIRE( ip.getLabel() == "tlabel" );
1002 REQUIRE( ip.getGroup() == "tgroup" );
1003 }
1004
1005 SECTION( "createStandardIndiToggleSw" )
1006 {
1007 MagAOXApp_test app;
1008 app.setConfigName( "testz" );
1009
1010 pcf::IndiProperty ip;
1011
1012 app.createStandardIndiToggleSw( ip, "tpropz", "tlabelz", "tgroupz" );
1013
1014 REQUIRE( ip.getType() == pcf::IndiProperty::Switch );
1015 REQUIRE( ip.getDevice() == "testz" );
1016 REQUIRE( ip.getName() == "tpropz" );
1017 REQUIRE( ip.getPerm() == pcf::IndiProperty::ReadWrite );
1018 REQUIRE( ip.getState() == pcf::IndiProperty::Idle );
1019 REQUIRE( ip.getRule() == pcf::IndiProperty::AtMostOne );
1020
1021 REQUIRE( ip.getNumElements() == 1 );
1022 REQUIRE( ip.find( "toggle" ) == true );
1023 REQUIRE( ip["toggle"].getSwitchState() == pcf::IndiElement::Off );
1024 REQUIRE( ip.getLabel() == "tlabelz" );
1025 REQUIRE( ip.getGroup() == "tgroupz" );
1026 }
1027
1028 SECTION( "createStandardIndiRequestSw" )
1029 {
1030 MagAOXApp_test app;
1031 app.setConfigName( "testz" );
1032
1033 pcf::IndiProperty ip;
1034
1035 app.createStandardIndiRequestSw( ip, "tpropz", "tlabelz", "tgroupz" );
1036
1037 REQUIRE( ip.getType() == pcf::IndiProperty::Switch );
1038 REQUIRE( ip.getDevice() == "testz" );
1039 REQUIRE( ip.getName() == "tpropz" );
1040 REQUIRE( ip.getPerm() == pcf::IndiProperty::ReadWrite );
1041 REQUIRE( ip.getState() == pcf::IndiProperty::Idle );
1042 REQUIRE( ip.getRule() == pcf::IndiProperty::AtMostOne );
1043
1044 REQUIRE( ip.getNumElements() == 1 );
1045 REQUIRE( ip.find( "request" ) == true );
1046 REQUIRE( ip["request"].getSwitchState() == pcf::IndiElement::Off );
1047 REQUIRE( ip.getLabel() == "tlabelz" );
1048 REQUIRE( ip.getGroup() == "tgroupz" );
1049 }
1050
1051 SECTION( "createStandardIndiSelectionSw, w/ labels" )
1052 {
1053 MagAOXApp_test app;
1054 app.setConfigName( "testy" );
1055
1056 pcf::IndiProperty ip;
1057
1058 std::vector<std::string> els( { "el1", "el2", "el3" } );
1059 std::vector<std::string> labs( { "l1", "", "l3" } );
1060
1061 app.createStandardIndiSelectionSw( ip, "tpropy", els, labs, "tlabely", "tgroupy" );
1062
1063 REQUIRE( ip.getType() == pcf::IndiProperty::Switch );
1064 REQUIRE( ip.getDevice() == "testy" );
1065 REQUIRE( ip.getName() == "tpropy" );
1066 REQUIRE( ip.getPerm() == pcf::IndiProperty::ReadWrite );
1067 REQUIRE( ip.getState() == pcf::IndiProperty::Idle );
1068 REQUIRE( ip.getRule() == pcf::IndiProperty::OneOfMany );
1069
1070 REQUIRE( ip.getNumElements() == 3 );
1071 REQUIRE( ip.find( "el1" ) == true );
1072 REQUIRE( ip["el1"].getSwitchState() == pcf::IndiElement::Off );
1073 REQUIRE( ip["el1"].getLabel() == "l1" );
1074
1075 REQUIRE( ip.find( "el2" ) == true );
1076 REQUIRE( ip["el2"].getSwitchState() == pcf::IndiElement::Off );
1077 REQUIRE( ip["el2"].getLabel() == "" );
1078
1079 REQUIRE( ip.find( "el3" ) == true );
1080 REQUIRE( ip["el3"].getSwitchState() == pcf::IndiElement::Off );
1081 REQUIRE( ip["el3"].getLabel() == "l3" );
1082
1083 REQUIRE( ip.getLabel() == "tlabely" );
1084 REQUIRE( ip.getGroup() == "tgroupy" );
1085 }
1086
1087 SECTION( "createStandardIndiSelectionSw, no labels" )
1088 {
1089 MagAOXApp_test app;
1090 app.setConfigName( "testy" );
1091
1092 pcf::IndiProperty ip;
1093
1094 std::vector<std::string> els( { "el1", "el2", "el3" } );
1095
1096 app.createStandardIndiSelectionSw( ip, "tpropy", els, "tlabely", "tgroupy" );
1097
1098 REQUIRE( ip.getType() == pcf::IndiProperty::Switch );
1099 REQUIRE( ip.getDevice() == "testy" );
1100 REQUIRE( ip.getName() == "tpropy" );
1101 REQUIRE( ip.getPerm() == pcf::IndiProperty::ReadWrite );
1102 REQUIRE( ip.getState() == pcf::IndiProperty::Idle );
1103 REQUIRE( ip.getRule() == pcf::IndiProperty::OneOfMany );
1104
1105 REQUIRE( ip.getNumElements() == 3 );
1106 REQUIRE( ip.find( "el1" ) == true );
1107 REQUIRE( ip["el1"].getSwitchState() == pcf::IndiElement::Off );
1108 REQUIRE( ip["el1"].getLabel() == "el1" );
1109
1110 REQUIRE( ip.find( "el2" ) == true );
1111 REQUIRE( ip["el2"].getSwitchState() == pcf::IndiElement::Off );
1112 REQUIRE( ip["el2"].getLabel() == "el2" );
1113
1114 REQUIRE( ip.find( "el3" ) == true );
1115 REQUIRE( ip["el3"].getSwitchState() == pcf::IndiElement::Off );
1116 REQUIRE( ip["el3"].getLabel() == "el3" );
1117
1118 REQUIRE( ip.getLabel() == "tlabely" );
1119 REQUIRE( ip.getGroup() == "tgroupy" );
1120 }
1121}
1122
1123/// Signal Handlers
1124/**
1125 * \ingroup MagAOXApp_unit_test
1126 */
1127TEST_CASE( "Signal Handlers", "[app::MagAOXApp]" )
1128{
1129 SECTION( "Setting and calling signal handler: SIGTERM" )
1130 {
1131
1132 MagAOXApp_test app;
1133
1134 // this is just to touch this function
1135 REQUIRE( app.setSigTermHandler() == 0 );
1136
1137 REQUIRE( app.shutdown() == 0 );
1138 app._handlerSigTerm( SIGTERM, nullptr, nullptr );
1139 REQUIRE( app.shutdown() == 1 );
1140 }
1141
1142 SECTION( "Setting and calling signal handler: SIGINT" )
1143 {
1144
1145 MagAOXApp_test app;
1146
1147 // this is just to touch this function
1148 REQUIRE( app.setSigTermHandler() == 0 );
1149
1150 REQUIRE( app.shutdown() == 0 );
1151 app._handlerSigTerm( SIGINT, nullptr, nullptr );
1152 REQUIRE( app.shutdown() == 1 );
1153 }
1154
1155 SECTION( "Setting and calling signal handler: SIGQUIT" )
1156 {
1157
1158 MagAOXApp_test app;
1159
1160 // this is just to touch this function
1161 REQUIRE( app.setSigTermHandler() == 0 );
1162
1163 REQUIRE( app.shutdown() == 0 );
1164 app._handlerSigTerm( SIGQUIT, nullptr, nullptr );
1165 REQUIRE( app.shutdown() == 1 );
1166 }
1167
1168 SECTION( "Setting and calling signal handler: SIGHUP" )
1169 {
1170
1171 MagAOXApp_test app;
1172
1173 // this is just to touch this function
1174 REQUIRE( app.setSigTermHandler() == 0 );
1175
1176 REQUIRE( app.shutdown() == 0 );
1177 app._handlerSigTerm( SIGHUP, nullptr, nullptr );
1178 REQUIRE( app.shutdown() == 1 );
1179 }
1180}
1181
1182/// Setting Euid
1183/**
1184 * \ingroup MagAOXApp_unit_test
1185 */
1186TEST_CASE( "Setting Euid", "[app::MagAOXApp]" )
1187{
1188
1189 MagAOXApp_test app;
1190
1191 REQUIRE( app.setEuidReal() == 0 );
1192
1193 REQUIRE( app.setEuidCalled() == 0 );
1194
1195 REQUIRE( app.setEuidReal( 0 ) == -1 );
1196 REQUIRE( app.setEuidCalled( 0 ) == -1 );
1197}
1198
1199/// Tests of utilities in cpp
1200/**
1201 * \ingroup MagAOXApp_unit_test
1202 */
1203TEST_CASE( "Tests of utilities in cpp", "[app::MagAOXApp]" )
1204{
1205 SECTION( "sigusr1 handler" )
1206 {
1207 // this is just to touch this function
1208 MagAOX::app::sigUsr1Handler( 0, nullptr, nullptr );
1209
1210 REQUIRE( true );
1211 }
1212}
1213
1214} // namespace MagAOXAppTest
1215} // namespace appTest
1216} // namespace libXWCTest
#define GIVEN(desc)
Definition catch.hpp:17763
#define WHEN(desc)
Definition catch.hpp:17765
#define TEST_CASE(...)
Definition catch.hpp:17712
#define SCENARIO(...)
Definition catch.hpp:17760
#define SECTION(...)
Definition catch.hpp:17716
#define REQUIRE(...)
Definition catch.hpp:17676
#define MAGAOX_calibRelPath
The relative path to the calibration files.
Definition paths.hpp:36
#define MAGAOX_configRelPath
The relative path to the configuration files.
Definition paths.hpp:29
#define MAGAOX_logRelPath
The relative path to the log directory.
Definition paths.hpp:50
#define MAGAOX_sysRelPath
The relative path to the system directory.
Definition paths.hpp:64
#define MAGAOX_path
The path to the MagAO-X system files.
Definition paths.hpp:22
#define MAGAOX_secretsRelPath
The relative path to the secrets directory. Used for storing passwords, etc.
Definition paths.hpp:71
#define MAGAOX_cpusetPath
The absolute path to the cpuset mount point.
Definition paths.hpp:99
#define MAGAOX_env_sys
Environment variable setting the relative system directory path.
#define MAGAOX_env_path
Environment variable setting the MagAO-X path.
#define MAGAOX_env_log
Environment variable setting the relative log path.
#define MAGAOX_env_calib
Environment variable setting the relative calib path.
#define MAGAOX_env_secrets
Environment variable setting the relative secrets path.
#define MAGAOX_env_config
Environment variable setting the relative config path.
#define MAGAOX_env_cpuset
Environment variable setting the cpu set path.
@ NODEVICE
No device exists for the application to control.
@ NOTHOMED
The device has not been homed.
@ HOMING
The device is homing.
@ READY
The device is ready for operation, but is not operating.
@ LOGGEDIN
The application has logged into the device or service.
void sigUsr1Handler(int signum, siginfo_t *siginf, void *ucont)
Empty signal handler. SIGUSR1 is used to interrupt sleep in various threads.
Definition MagAOXApp.cpp:18
int callback(void *app, const pcf::IndiProperty &ipRecv)
void _handlerSigTerm(int signum, siginfo_t *siginf, void *ucont)
void configurePowerManagement(const std::string &device, const std::string &channel)
void configurePowerOnWait(unsigned long powerOnWait, int powerOnCounter, int loopPause)
int setPowerState(const std::string &state, const std::string target)