vendor(qemu-ga): svos-dev's nh3-svos quiesce hook + its 6 controls beside the dispatcher
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import importlib.machinery,importlib.util,json,subprocess,tempfile,unittest
|
||||
from pathlib import Path
|
||||
|
||||
class QuiesceTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp=tempfile.TemporaryDirectory();self.addCleanup(self.tmp.cleanup)
|
||||
self.directory=Path(self.tmp.name)
|
||||
# the installed hook has no .py suffix (50-svos), so give the loader explicitly; path is relative to this file
|
||||
loader=importlib.machinery.SourceFileLoader('svos_quiesce',str(Path(__file__).with_name('50-svos')))
|
||||
spec=importlib.util.spec_from_loader('svos_quiesce',loader)
|
||||
self.module=importlib.util.module_from_spec(spec);spec.loader.exec_module(self.module)
|
||||
self.states={'svos-kernel.service':('active','success'),'svos-interface.service':('inactive','success')}
|
||||
self.calls=[];self.stop_fail=False;self.start_fail=False;self.dirty_stop=False
|
||||
def run(args,**kwargs):
|
||||
self.calls.append(args)
|
||||
if args[0]=='show':
|
||||
state,result=self.states[args[1]]
|
||||
return subprocess.CompletedProcess(args,0,f'ActiveState={state}\nResult={result}\n','')
|
||||
units=[x for x in args[1:] if not x.startswith('--')]
|
||||
if args[0]=='stop':
|
||||
self.states[units[0]]=('inactive','timeout' if self.dirty_stop else 'success')
|
||||
if self.stop_fail:raise subprocess.TimeoutExpired(args,35)
|
||||
for unit in units:self.states[unit]=('inactive','timeout' if self.dirty_stop else 'success')
|
||||
elif args[0]=='start':
|
||||
if self.start_fail:raise subprocess.CalledProcessError(1,args)
|
||||
for unit in units:self.states[unit]=('active','success')
|
||||
return subprocess.CompletedProcess(args,0,'','')
|
||||
self.q=self.module.Quiesce(self.directory,run=run)
|
||||
def test_restore_only_previously_active_services(self):
|
||||
self.q.freeze();self.assertEqual(self.states['svos-kernel.service'][0],'inactive')
|
||||
self.assertEqual(self.states['svos-interface.service'][0],'inactive')
|
||||
self.q.thaw();self.assertEqual(self.states['svos-kernel.service'][0],'active')
|
||||
self.assertEqual(self.states['svos-interface.service'][0],'inactive')
|
||||
self.assertFalse(self.q.state.exists());self.q.thaw()
|
||||
def test_stop_timeout_refuses_freeze_and_schedules_recovery(self):
|
||||
self.stop_fail=True
|
||||
with self.assertRaises(subprocess.TimeoutExpired):self.q.freeze()
|
||||
self.assertEqual(self.states['svos-kernel.service'][0],'active')
|
||||
self.assertTrue(self.q.state.exists())
|
||||
self.q.thaw();self.assertFalse(self.q.state.exists())
|
||||
def test_unclean_stop_is_not_reported_as_consistent(self):
|
||||
self.dirty_stop=True
|
||||
with self.assertRaises(RuntimeError):self.q.freeze()
|
||||
self.assertEqual(self.states['svos-kernel.service'][0],'active')
|
||||
def test_failed_thaw_preserves_recovery_record(self):
|
||||
self.q.freeze();self.start_fail=True
|
||||
with self.assertRaises(subprocess.CalledProcessError):self.q.thaw()
|
||||
self.assertTrue(self.q.state.exists());self.start_fail=False
|
||||
self.q.thaw();self.assertFalse(self.q.state.exists())
|
||||
def test_repeated_freeze_cannot_overwrite_original_running_set(self):
|
||||
self.q.freeze();before=self.q.state.read_bytes()
|
||||
with self.assertRaises(RuntimeError):self.q.freeze()
|
||||
self.assertEqual(self.q.state.read_bytes(),before)
|
||||
self.q.thaw();self.assertEqual(self.states['svos-kernel.service'][0],'active')
|
||||
def test_transition_refuses_before_any_stop(self):
|
||||
self.states['svos-interface.service']=('deactivating','success')
|
||||
with self.assertRaises(RuntimeError):self.q.freeze()
|
||||
self.assertFalse(self.q.state.exists())
|
||||
self.assertFalse(any(x[0]=='stop' for x in self.calls))
|
||||
|
||||
if __name__=='__main__':unittest.main()
|
||||
Reference in New Issue
Block a user