36namespace zaberLowLevelTest
44 zaberLowLevel_test(
const std::string &device )
46 m_configName = device;
58 int setupPowerOffSnapshot(
const std::string &stageName,
long rawPos,
bool parked,
long maxPos, time_t lastHomed )
62 m_testRoot = std::filesystem::temp_directory_path() / (
"zaberLowLevel_test_" + m_configName );
63 std::filesystem::remove_all( m_testRoot, ec );
65 m_basePath = m_testRoot.string();
66 m_sysPath = ( m_testRoot /
"sys" ).
string();
69 std::filesystem::create_directories( std::filesystem::path( m_sysPath ) / m_configName );
71 m_stages.emplace_back(
this );
72 m_stages.back().name( stageName );
73 m_stages.back().serial(
"serial0" );
76 std::ofstream stateOut( std::filesystem::path( m_sysPath ) / m_configName / stageName );
77 stateOut << rawPos <<
'\n' << parked <<
'\n' << maxPos <<
'\n' << lastHomed <<
'\n';
80 if( appStartup() < 0 )
85 if( createINDIFIFOS() < 0 )
92 return ( m_indiDriver && m_indiDriver->good() ) ? 0 : -1;
96 int addConfiguredStage(
const std::string &stageName,
const std::string &serial,
int deviceAddress = -1 )
98 m_stages.emplace_back(
this );
99 m_stages.back().name( stageName );
100 m_stages.back().serial( serial );
101 m_stages.back().deviceAddress( deviceAddress );
103 const size_t idx = m_stages.size() - 1;
105 m_stageName.insert( { stageName, idx } );
106 m_stageSerial.insert( { serial, idx } );
112 int loadParsedStages( std::string serialResponse )
114 return loadStages( serialResponse );
118 int setDeviceAddressFor(
size_t stageIndex,
int deviceAddress )
120 m_stages.at( stageIndex ).deviceAddress( deviceAddress );
125 int deviceAddressFor(
size_t stageIndex )
const
127 return m_stages.at( stageIndex ).deviceAddress();
131 int recoverTransportError(
bool devicePresent )
133 return recoverFromError( devicePresent );
150 std::string propertyValue(
const pcf::IndiProperty &property,
const std::string &element )
const
152 return property[element].getValue();
156 std::string currPosValue(
const std::string &stageName )
const
158 return propertyValue( m_indiP_curr_pos, stageName );
162 std::string tgtPosValue(
const std::string &stageName )
const
164 return propertyValue( m_indiP_tgt_pos, stageName );
168 std::string parkedValue(
const std::string &stageName )
const
170 return propertyValue( m_indiP_parked, stageName );
174 std::string lastHomedValue(
const std::string &stageName )
const
176 return propertyValue( m_indiP_lastHomed, stageName );
180 std::string maxPosValue(
const std::string &stageName )
const
182 return propertyValue( m_indiP_max_pos, stageName );
186 std::string currStateValue(
const std::string &stageName )
const
188 return propertyValue( m_indiP_curr_state, stageName );
192 std::string warnValue(
const std::string &stageName )
const
194 return propertyValue( m_indiP_warn, stageName );
203 ~zaberLowLevel_test()
noexcept
208 m_indiDriver =
nullptr;
209 std::filesystem::remove_all( m_testRoot, ec );
213 std::filesystem::path m_testRoot;
224 #ifdef ZABERLOWLEVEL_TEST_DOXYGEN_REF
225 zaberLowLevel::newCallBack_m_indiP_tgt_pos( pcf::IndiProperty() );
226 zaberLowLevel::newCallBack_m_indiP_req_home( pcf::IndiProperty() );
240SCENARIO(
"Power-off INDI snapshot retains stage state",
"[zaberLowLevel]" )
242 zaberLowLevel_test zllt(
"zlltest" );
244 REQUIRE( zllt.setupPowerOffSnapshot(
"stageA", 12345,
true, 54321, 77 ) == 0 );
246 REQUIRE( zllt.doOnPowerOff() == 0 );
248 REQUIRE( zllt.currPosValue(
"stageA" ) ==
"12345" );
249 REQUIRE( zllt.tgtPosValue(
"stageA" ) ==
"12345" );
250 REQUIRE( zllt.parkedValue(
"stageA" ) ==
"1" );
251 REQUIRE( zllt.lastHomedValue(
"stageA" ) ==
"77" );
252 REQUIRE( zllt.maxPosValue(
"stageA" ) ==
"54321" );
253 REQUIRE( zllt.currStateValue(
"stageA" ) ==
"POWEROFF" );
254 REQUIRE( zllt.warnValue(
"stageA" ) ==
"Off" );
261SCENARIO(
"Stage discovery resets stale device addresses",
"[zaberLowLevel]" )
264 #ifdef ZABERLOWLEVEL_TEST_DOXYGEN_REF
269 zaberLowLevel_test zllt(
"zlltest" );
271 REQUIRE( zllt.addConfiguredStage(
"stagebs",
"49820", 1 ) == 0 );
272 REQUIRE( zllt.addConfiguredStage(
"stageirf",
"49821", 2 ) == 0 );
274 std::string serialResponse =
"@01 0 OK IDLE WR 49820\n";
276 REQUIRE( zllt.loadParsedStages( serialResponse ) ==
ZC_CONNECTED );
277 REQUIRE( zllt.deviceAddressFor( 0 ) == 1 );
278 REQUIRE( zllt.deviceAddressFor( 1 ) < 1 );
285SCENARIO(
"Stage discovery can find devices that appear later",
"[zaberLowLevel]" )
287 zaberLowLevel_test zllt(
"zlltest_rediscover" );
289 REQUIRE( zllt.addConfiguredStage(
"stagebs",
"49820" ) == 0 );
290 REQUIRE( zllt.addConfiguredStage(
"stageirf",
"49821" ) == 0 );
292 std::string serialResponse1 =
"@01 0 OK IDLE WR 49820\n";
293 std::string serialResponse2 =
"@01 0 OK IDLE WR 49820\n@02 0 OK IDLE WR 49821\n";
295 REQUIRE( zllt.loadParsedStages( serialResponse1 ) ==
ZC_CONNECTED );
296 REQUIRE( zllt.deviceAddressFor( 0 ) == 1 );
297 REQUIRE( zllt.deviceAddressFor( 1 ) < 1 );
299 REQUIRE( zllt.loadParsedStages( serialResponse2 ) ==
ZC_CONNECTED );
300 REQUIRE( zllt.deviceAddressFor( 0 ) == 1 );
301 REQUIRE( zllt.deviceAddressFor( 1 ) == 2 );
308SCENARIO(
"Recoverable transport errors transition to reconnect states",
"[zaberLowLevel]" )
311 #ifdef ZABERLOWLEVEL_TEST_DOXYGEN_REF
317 SECTION(
"A present tty returns the app to NOTCONNECTED" )
319 zaberLowLevel_test zllt(
"zlltest_present" );
321 REQUIRE( zllt.setupPowerOffSnapshot(
"stageA", 12345,
true, 54321, 77 ) == 0 );
322 REQUIRE( zllt.setDeviceAddressFor( 0, 1 ) == 0 );
325 REQUIRE( zllt.recoverTransportError(
true ) == 0 );
327 REQUIRE( zllt.currStateValue(
"stageA" ) ==
"NOTCONNECTED" );
330 SECTION(
"A missing tty returns the app to NODEVICE" )
332 zaberLowLevel_test zllt(
"zlltest_missing" );
334 REQUIRE( zllt.setupPowerOffSnapshot(
"stageA", 12345,
true, 54321, 77 ) == 0 );
335 REQUIRE( zllt.setDeviceAddressFor( 0, 1 ) == 0 );
338 REQUIRE( zllt.recoverTransportError(
false ) == 0 );
340 REQUIRE( zllt.currStateValue(
"stageA" ) ==
"NODEVICE" );