class TestVirtualMachine(IsolatedAsyncioTestCase): _server: TrueNASServer _machine: CachingMachine def setUp(self): self._server = TrueNASServer() async def asyncSetUp(self): self._machine = await CachingMachine.create( self._server.host, username=self._server.username, password=self._server.password, secure=False, ) async def asyncTearDown(self): await self._machine.close() await self._server.stop() async def test_running_data_interpretation(self) -> None: DESCRIPTION = "Some Desc" ID = 1 NAME = "vm01" self._server.register_method_handler( "vm.query", lambda *args: [ { "description": DESCRIPTION, "id": ID, "name": NAME, "status": { "pid": 42, "state": "RUNNING" }, }, ], ) await self._machine.get_vms() self.assertEqual(len(self._machine.vms), 1) vm = self._machine.vms[0] self.assertEqual(vm.description, DESCRIPTION) self.assertEqual(vm.id, ID) self.assertEqual(vm.name, NAME) self.assertEqual(vm.status, VirtualMachineState.RUNNING) async def test_stopped_data_interpretation(self) -> None: DESCRIPTION = "" ID = 3 NAME = "vm02" self._server.register_method_handler( "vm.query", lambda *args: [ { "description": DESCRIPTION, "id": ID, "name": NAME, "status": { "pid": None, "state": "STOPPED" }, }, ], ) await self._machine.get_vms() self.assertEqual(len(self._machine.vms), 1) vm = self._machine.vms[0] self.assertEqual(vm.description, DESCRIPTION) self.assertEqual(vm.id, ID) self.assertEqual(vm.name, NAME) self.assertEqual(vm.status, VirtualMachineState.STOPPED) async def test_availability(self) -> None: self._server.register_method_handler( "vm.query", lambda *args: [ { "description": "Some Desc", "id": 1, "name": "vm01", "status": { "pid": 42, "state": "RUNNING" }, }, ], ) await self._machine.get_vms() vm = self._machine.vms[0] self.assertTrue(vm.available) self._server.register_method_handler( "vm.query", lambda *args: [], override=True, ) await self._machine.get_vms() self.assertFalse(vm.available) self.assertEqual(len(self._machine.vms), 0) async def test_unavailable_caching(self) -> None: """Certain properites have caching even if no longer available""" DESCRIPTION = "Some Desc" ID = 1 NAME = "vm01" self._server.register_method_handler( "vm.query", lambda *args: [ { "description": DESCRIPTION, "id": ID, "name": NAME, "status": { "pid": 42, "state": "RUNNING" }, }, ], ) await self._machine.get_vms() vm = self._machine.vms[0] assert vm is not None self._server.register_method_handler( "vm.query", lambda *args: [], override=True, ) await self._machine.get_vms() self.assertEqual(vm.description, DESCRIPTION) self.assertEqual(vm.id, ID) self.assertEqual(vm.name, NAME) with self.assertRaises(AssertionError): vm.status async def test_same_instance_after_get_vms(self) -> None: self._server.register_method_handler( "vm.query", lambda *args: [ { "description": "Some Desc", "id": 1, "name": "vm01", "status": { "pid": 42, "state": "RUNNING" }, }, ], ) await self._machine.get_vms() original_vm = self._machine.vms[0] await self._machine.get_vms() new_vm = self._machine.vms[0] self.assertIs(original_vm, new_vm) async def test_start(self) -> None: ID = 42 self._server.register_method_handler( "vm.query", lambda *args: [ { "description": "Some Desc", "id": 42, "name": "vm01", "status": { "pid": None, "state": "STOPPED" }, }, ], ) def start_handler(id, kwargs) -> None: self.assertEqual(id, ID) self.assertFalse(kwargs["overcommit"]) return None self._server.register_method_handler( "vm.start", start_handler, ) await self._machine.get_vms() vm = self._machine.vms[0] assert vm is not None self.assertEqual(await vm.start(), None) async def test_stop(self) -> None: ID = 42 self._server.register_method_handler( "vm.query", lambda *args: [ { "description": "Some Desc", "id": 42, "name": "vm01", "status": { "pid": 10, "state": "RUNNING" }, }, ], ) def stop_handler(id, options: Dict[str, bool]) -> TJobId: JOB_ID = 42 self.assertEqual(id, ID) self.assertFalse(options["force_after_timeout"]) self._server.send_subscription_data({ "msg": "changed", "collection": "core.get_jobs", "id": JOB_ID, "fields": { "id": JOB_ID, "method": "vm.stop", "arguments": [ID, { "force_after_timeout": False }], "logs_path": None, "logs_excerpt": None, "progress": { "percent": 100, "description": None, "extra": None, }, "result": None, "error": None, "exception": None, "exc_info": None, "state": "SUCCESS", "time_started": datetime.datetime(2021, 1, 8, 21, 30, 0, tzinfo=datetime.timezone.utc), "time_finished": datetime.datetime(2021, 1, 8, 21, 30, 1, tzinfo=datetime.timezone.utc), }, }) return JOB_ID self._server.register_method_handler( "vm.stop", stop_handler, ) self._server.register_method_handler( "vm.status", lambda id: { "state": "STOPPED", "pid": 42, "domain_state": "STOPPED" }, ) await self._machine.get_vms() vm = self._machine.vms[0] assert vm is not None self.assertTrue(await vm.stop()) async def test_restart(self) -> None: ID = 42 self._server.register_method_handler( "vm.query", lambda *args: [ { "description": "Some Desc", "id": 42, "name": "vm01", "status": { "pid": 10, "state": "RUNNING" }, }, ], ) def restart_handler(id) -> TJobId: JOB_ID = 42 self.assertEqual(id, ID) self._server.send_subscription_data({ "msg": "changed", "collection": "core.get_jobs", "id": JOB_ID, "fields": { "id": JOB_ID, "method": "vm.restart", "arguments": [ID], "logs_path": None, "logs_excerpt": None, "progress": { "percent": 100, "description": None, "extra": None, }, "result": None, "error": None, "exception": None, "exc_info": None, "state": "SUCCESS", "time_started": datetime.datetime(2021, 1, 8, 21, 30, 0, tzinfo=datetime.timezone.utc), "time_finished": datetime.datetime(2021, 1, 8, 21, 30, 1, tzinfo=datetime.timezone.utc), }, }) return JOB_ID self._server.register_method_handler( "vm.restart", restart_handler, ) self._server.register_method_handler( "vm.status", lambda id: { "state": "RUNNING", "pid": 42, "domain_state": "RUNNING" }, ) await self._machine.get_vms() vm = self._machine.vms[0] assert vm is not None self.assertTrue(await vm.restart()) def test_eq_impl(self) -> None: self._machine._vm_fetcher._state = { # type: ignore "42": { "description": "", "id": 42, "name": "somename", "status": { "pid": 10, "state": "RUNNING" }, } } a = CachingVirtualMachine(self._machine._vm_fetcher, 42) # type: ignore b = CachingVirtualMachine(self._machine._vm_fetcher, 42) # type: ignore self.assertEqual(a, b)
class TestJail(IsolatedAsyncioTestCase): _server: TrueNASServer _machine: CachingMachine def setUp(self): self._server = TrueNASServer() async def asyncSetUp(self): self._machine = await CachingMachine.create( self._server.host, api_key=self._server.api_key, secure=False, ) async def asyncTearDown(self): await self._machine.close() await self._server.stop() async def test_running_data_interpretation(self) -> None: NAME = "jail01" self._server.register_method_handler( "jail.query", lambda *args: [ { "id": NAME, "state": "up", }, ], ) await self._machine.get_jails() self.assertEqual(len(self._machine.jails), 1) jail = self._machine.jails[0] self.assertEqual(jail.name, NAME) self.assertEqual(jail.status, JailStatus.UP) async def test_stopped_data_interpretation(self) -> None: NAME = "jail01" self._server.register_method_handler( "jail.query", lambda *args: [ { "id": NAME, "state": "down", }, ], ) await self._machine.get_jails() self.assertEqual(len(self._machine.jails), 1) jail = self._machine.jails[0] self.assertEqual(jail.name, NAME) self.assertEqual(jail.status, JailStatus.DOWN) async def test_availability(self) -> None: self._server.register_method_handler( "jail.query", lambda *args: [ { "id": "jail01", "state": "up", }, ], ) await self._machine.get_jails() jail = self._machine.jails[0] self.assertTrue(jail.available) self._server.register_method_handler( "jail.query", lambda *args: [], override=True, ) await self._machine.get_jails() self.assertFalse(jail.available) self.assertEqual(len(self._machine.jails), 0) async def test_same_instance_after_get_jails(self) -> None: self._server.register_method_handler( "jail.query", lambda *args: [ { "id": "jail01", "state": "up", }, ], ) await self._machine.get_jails() original_jail = self._machine.jails[0] await self._machine.get_jails() new_jail = self._machine.jails[0] self.assertIs(original_jail, new_jail) async def test_start(self) -> None: NAME = "jail01" self._server.register_method_handler( "jail.query", lambda *args: [ { "id": NAME, "state": "up", }, ], ) await self._machine.get_jails() jail = self._machine.jails[0] with self.assertRaises(RuntimeError): await jail.start() self._server.register_method_handler( "jail.query", lambda *args: [ { "id": NAME, "state": "down", }, ], override=True, ) def start_handler(name) -> int: JOB_ID = 42 self.assertEqual(name, NAME) self._server.send_subscription_data( { "msg": "changed", "collection": "core.get_jobs", "id": JOB_ID, "fields": { "id": JOB_ID, "method": "jail.start", "arguments": [NAME], "logs_path": None, "logs_excerpt": None, "progress": { "percent": 100, "description": None, "extra": None, }, "result": True, "error": None, "exception": None, "exc_info": None, "state": "SUCCESS", "time_started": datetime.datetime(2021, 1, 7, 21, 30, 0, tzinfo=datetime.timezone.utc), "time_finished": datetime.datetime(2021, 1, 7, 21, 30, 1, tzinfo=datetime.timezone.utc), }, }, ), return JOB_ID self._server.register_method_handler( "jail.start", start_handler, ) await self._machine.get_jails() jail = self._machine.jails[0] self.assertTrue(await jail.start()) async def test_stop(self) -> None: NAME = "jail01" self._server.register_method_handler( "jail.query", lambda *args: [ { "id": NAME, "state": "down", }, ], ) await self._machine.get_jails() jail = self._machine.jails[0] with self.assertRaises(RuntimeError): await jail.stop() self._server.register_method_handler( "jail.query", lambda *args: [ { "id": NAME, "state": "up", }, ], override=True, ) def stop_handler(name, force) -> int: JOB_ID = 42 self.assertEqual(name, NAME) self.assertFalse(force) self._server.send_subscription_data( { "msg": "changed", "collection": "core.get_jobs", "id": JOB_ID, "fields": { "id": JOB_ID, "method": "jail.stop", "arguments": [NAME], "logs_path": None, "logs_excerpt": None, "progress": { "percent": 100, "description": None, "extra": None, }, "result": None, # For some reason, TrueNAS has a null result for this... "error": None, "exception": None, "exc_info": None, "state": "SUCCESS", "time_started": datetime.datetime(2021, 1, 7, 21, 30, 0, tzinfo=datetime.timezone.utc), "time_finished": datetime.datetime(2021, 1, 7, 21, 30, 1, tzinfo=datetime.timezone.utc), }, }, ) return JOB_ID self._server.register_method_handler( "jail.stop", stop_handler, ) await self._machine.get_jails() jail = self._machine.jails[0] self.assertTrue(await jail.stop()) async def test_restart(self) -> None: NAME = "jail01" self._server.register_method_handler( "jail.query", lambda *args: [ { "id": NAME, "state": "down", }, ], ) await self._machine.get_jails() jail = self._machine.jails[0] with self.assertRaises(RuntimeError): await jail.restart() self._server.register_method_handler( "jail.query", lambda *args: [ { "id": NAME, "state": "up", }, ], override=True, ) def restart_handler(name) -> int: JOB_ID = 42 self.assertEqual(name, NAME) self._server.send_subscription_data( { "msg": "changed", "collection": "core.get_jobs", "id": JOB_ID, "fields": { "id": JOB_ID, "method": "jail.start", "arguments": [NAME], "logs_path": None, "logs_excerpt": None, "progress": { "percent": 100, "description": None, "extra": None, }, "result": True, "error": None, "exception": None, "exc_info": None, "state": "SUCCESS", "time_started": datetime.datetime(2021, 1, 7, 21, 30, 0, tzinfo=datetime.timezone.utc), "time_finished": datetime.datetime(2021, 1, 7, 21, 30, 1, tzinfo=datetime.timezone.utc), }, }, ), return JOB_ID self._server.register_method_handler( "jail.restart", restart_handler, ) await self._machine.get_jails() jail = self._machine.jails[0] self.assertTrue(await jail.restart()) def test_eq_impl(self) -> None: self._machine._jail_fetcher._state = { # type: ignore "jail01": { "id": "jail01", "state": "up" } } a = CachingJail(self._machine._jail_fetcher, "jail01") # type: ignore b = CachingJail(self._machine._jail_fetcher, "jail01") # type: ignore self.assertEqual(a, b)