class TestCachingMachineGetSystemInfo(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_get_system_info(self) -> None:
        HOSTNAME = "some.hostname.com"
        self._server.register_method_handler(
            "system.info",
            lambda *args: {
                "hostname": HOSTNAME,
            },
        )

        info = await self._machine.get_system_info()

        self.assertTrue("hostname" in info)
        self.assertEqual(info["hostname"], HOSTNAME)
class TestPool(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_pool_data_interpretation(self) -> None:
        ENCRYPT = 0
        GUID = "1234ABCD"
        ID = 100
        IS_DECRYPTED = True
        NAME = "testpool"
        self._server.register_method_handler(
            "pool.query",
            lambda *args: [
                {
                    "encrypt": ENCRYPT,
                    "encryptkey": "",
                    "guid": GUID,
                    "id": ID,
                    "is_decrypted": IS_DECRYPTED,
                    "name": NAME,
                    "status": "ONLINE",
                    "state": "FINISHED",
                    "topology": {},
                },
            ],
        )

        await self._machine.get_pools()

        self.assertEqual(len(self._machine.pools), 1)
        pool = self._machine.pools[0]
        self.assertEqual(pool.encrypt, ENCRYPT)
        self.assertEqual(pool.guid, GUID)
        self.assertEqual(pool.id, ID)
        self.assertEqual(pool.is_decrypted, IS_DECRYPTED)
        self.assertEqual(pool.name, NAME)
        self.assertEqual(pool.status, PoolStatus.ONLINE)
        # Need to work on the return type of scan.state
        # self.assertEqual(pool.scan["state"], PoolScanState.FINISHED)

    async def test_availability(self) -> None:
        ENCRYPT = 0
        GUID = "1234ABCD"
        ID = 100
        IS_DECRYPTED = True
        NAME = "testpool"
        self._server.register_method_handler(
            "pool.query",
            lambda *args: [
                {
                    "encrypt": ENCRYPT,
                    "encryptkey": "",
                    "guid": GUID,
                    "id": ID,
                    "is_decrypted": IS_DECRYPTED,
                    "name": NAME,
                    "status": "ONLINE",
                    "topology": {},
                },
            ],
        )

        await self._machine.get_pools()

        pool = self._machine.pools[0]
        self.assertTrue(pool.available)

        self._server.register_method_handler(
            "pool.query",
            lambda *args: [],
            override=True,
        )
        await self._machine.get_pools()
        self.assertFalse(pool.available)
        self.assertEqual(len(self._machine.pools), 0)

    async def test_unavailable_caching(self) -> None:
        """Certain properites have caching even if no longer available"""
        ENCRYPT = 0
        GUID = "1234ABCD"
        ID = 100
        IS_DECRYPTED = True
        NAME = "testpool"
        self._server.register_method_handler(
            "pool.query",
            lambda *args: [
                {
                    "encrypt": ENCRYPT,
                    "encryptkey": "",
                    "guid": GUID,
                    "id": ID,
                    "is_decrypted": IS_DECRYPTED,
                    "name": NAME,
                    "status": "ONLINE",
                    "topology": {},
                },
            ],
        )
        await self._machine.get_pools()
        pool = self._machine.pools[0]
        assert pool is not None
        self._server.register_method_handler(
            "pool.query",
            lambda *args: [],
            override=True,
        )
        await self._machine.get_pools()

        self.assertEqual(pool.encrypt, ENCRYPT)
        self.assertEqual(pool.guid, GUID)
        self.assertEqual(pool.id, ID)
        self.assertEqual(pool.is_decrypted, IS_DECRYPTED)
        self.assertEqual(pool.name, NAME)
        self.assertEqual(pool.status, PoolStatus.ONLINE)

    async def test_same_instance_after_get_pools(self) -> None:
        self._server.register_method_handler(
            "pool.query",
            lambda *args: [
                {
                    "guid": 500,
                    "name": "test_pool",
                },
            ],
        )
        await self._machine.get_pools()
        original_pool = self._machine.pools[0]
        await self._machine.get_pools()
        new_pool = self._machine.pools[0]
        self.assertIs(original_pool, new_pool)

    def test_eq_impl(self) -> None:
        self._machine._pool_fetcher._state = {  # type: ignore
            "200": {
                "guid": 200,
                "name": "test_pool",
            }
        }
        a = CachingPool(self._machine._pool_fetcher, "200")  # type: ignore
        b = CachingPool(self._machine._pool_fetcher, "200")  # type: ignore
        self.assertEqual(a, b)
Beispiel #3
0
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, force) -> bool:
            self.assertEqual(id, ID)
            self.assertFalse(force)
            return True

        self._server.register_method_handler(
            "vm.stop",
            stop_handler,
        )
        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) -> bool:
            self.assertEqual(id, ID)
            return True

        self._server.register_method_handler(
            "vm.restart",
            restart_handler,
        )
        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 = {
            42: {
                "description": "",
                "id": 42,
                "name": "somename",
                "status": {
                    "pid": 10,
                    "state": "RUNNING"
                },
            }
        }
        a = CachingVirtualMachine(self._machine._vm_fetcher, 42)
        b = CachingVirtualMachine(self._machine._vm_fetcher, 42)
        self.assertEqual(a, b)
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)
Beispiel #5
0
class TestDisk(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_ssd_data_interpretation(self) -> None:
        DESCRIPTION = "Some Desc"
        MODEL = "Samsung SSD 860 EVO 250GB"
        NAME = "ada0"
        SERIAL = "NOTREALSERIAL"
        SIZE = 250059350016
        self._server.register_method_handler(
            "disk.query",
            lambda *args: [
                {
                    "description": DESCRIPTION,
                    "model": MODEL,
                    "name": NAME,
                    "serial": SERIAL,
                    "size": SIZE,
                    "type": "SSD",
                },
            ],
        )

        await self._machine.get_disks()

        self.assertEqual(len(self._machine.disks), 1)
        disk = self._machine.disks[0]
        self.assertEqual(
            disk.description,
            DESCRIPTION,
        )
        self.assertEqual(disk.model, MODEL)
        self.assertEqual(disk.name, NAME)
        self.assertEqual(disk.serial, SERIAL)
        self.assertEqual(disk.size, SIZE)
        self.assertEqual(disk.temperature, None)
        self.assertEqual(disk.type, DiskType.SSD)

    async def test_hddd_data_interpretation(self) -> None:
        DESCRIPTION = "Some Desc"
        MODEL = "ATA WDC WD60EFAX-68S"
        NAME = "da0"
        SERIAL = "NOTREALSERIAL"
        SIZE = 6001175126016
        self._server.register_method_handler(
            "disk.query",
            lambda *args: [
                {
                    "description": DESCRIPTION,
                    "model": MODEL,
                    "name": NAME,
                    "serial": SERIAL,
                    "size": SIZE,
                    "type": "HDD",
                },
            ],
        )

        await self._machine.get_disks()

        self.assertEqual(len(self._machine.disks), 1)
        disk = self._machine.disks[0]
        self.assertEqual(
            disk.description,
            DESCRIPTION,
        )
        self.assertEqual(disk.model, MODEL)
        self.assertEqual(disk.name, NAME)
        self.assertEqual(disk.serial, SERIAL)
        self.assertEqual(disk.size, SIZE)
        self.assertEqual(disk.temperature, None)
        self.assertEqual(disk.type, DiskType.HDD)

    async def test_temperature(self) -> None:
        TEMPERATURE = 42
        self._server.register_method_handler(
            "disk.query",
            lambda *args: [
                {
                    "description": "Some Desc",
                    "model": "Samsung SSD 860 EVO 250GB",
                    "name": "ada0",
                    "serial": "NOTREALSERIAL",
                    "size": 250059350016,
                    "type": "SSD",
                },
            ],
        )
        self._server.register_method_handler(
            "disk.temperatures",
            lambda *args: {"ada0": TEMPERATURE},
        )

        await self._machine.get_disks(include_temperature=True)

        self.assertEqual(len(self._machine.disks), 1)
        disk = self._machine.disks[0]
        self.assertEqual(disk.temperature, TEMPERATURE)

    async def test_availability(self) -> None:
        self._server.register_method_handler(
            "disk.query",
            lambda *args: [
                {
                    "description": "Some Desc",
                    "model": "Samsung SSD 860 EVO 250GB",
                    "name": "ada0",
                    "serial": "NOTREALSERIAL",
                    "size": 250059350016,
                    "type": "SSD",
                },
            ],
        )
        self._server.register_method_handler(
            "disk.temperatures",
            lambda *args: {"ada0": 42},
        )

        await self._machine.get_disks()

        disk = self._machine.disks[0]
        self.assertTrue(disk.available)

        self._server.register_method_handler(
            "disk.query",
            lambda *args: [],
            override=True,
        )
        await self._machine.get_disks()
        self.assertFalse(disk.available)
        self.assertEqual(
            len(self._machine._disk_fetcher._cached_disks),
            0  # type: ignore
        )

    async def test_unavailable_caching(self) -> None:
        """Certain properites have caching even if no longer available"""
        DESCRIPTION = "Some Desc"
        MODEL = "ATA WDC WD60EFAX-68S"
        NAME = "da0"
        SERIAL = "NOTREALSERIAL"
        SIZE = 6001175126016
        self._server.register_method_handler(
            "disk.query",
            lambda *args: [
                {
                    "description": DESCRIPTION,
                    "model": MODEL,
                    "name": NAME,
                    "serial": SERIAL,
                    "size": SIZE,
                    "type": "HDD",
                },
            ],
        )
        self._server.register_method_handler(
            "disk.temperatures",
            lambda *args: {NAME: 42},
        )
        await self._machine.get_disks()
        disk = self._machine.disks[0]
        assert disk is not None
        self._server.register_method_handler(
            "disk.query",
            lambda *args: [],
            override=True,
        )
        await self._machine.get_disks()

        self.assertEqual(disk.model, MODEL)
        self.assertEqual(disk.name, NAME)
        self.assertEqual(disk.serial, SERIAL)
        self.assertEqual(disk.size, SIZE)
        with self.assertRaises(AssertionError):
            disk.temperature
        self.assertEqual(disk.type, DiskType.HDD)

    async def test_same_instance_after_get_disks(self) -> None:
        self._server.register_method_handler(
            "disk.query",
            lambda *args: [
                {
                    "description": "Some Desc",
                    "model": "Samsung SSD 860 EVO 250GB",
                    "name": "ada0",
                    "serial": "NOTREALSERIAL",
                    "size": 250059350016,
                    "type": "SSD",
                },
            ],
        )
        self._server.register_method_handler(
            "disk.temperatures",
            lambda *args: {"ada0": 42},
        )
        await self._machine.get_disks()
        original_disk = self._machine.disks[0]
        await self._machine.get_disks()
        new_disk = self._machine.disks[0]
        self.assertIs(original_disk, new_disk)

    def test_eq_impl(self) -> None:
        self._machine._disk_fetcher._state = {  # type: ignore
            "ada0": {
                "description": "",
                "model": "",
                "name": "ada0",
                "serial": "someserial",
                "size": 256,
                "temperature": 42,
                "type": "SSD",
            }
        }
        a = CachingDisk(self._machine._disk_fetcher, "ada0")  # type: ignore
        b = CachingDisk(self._machine._disk_fetcher, "ada0")  # type: ignore
        self.assertEqual(a, b)

    async def test_serial_with_edge_whitespace(self) -> None:
        SERIAL = "NOTREALSERIAL"
        self._server.register_method_handler(
            "disk.query",
            lambda *args: [
                {
                    "description": "Some Desc",
                    "model": "Samsung SSD 860 EVO 250GB",
                    "name": "ada0",
                    "serial": f" {SERIAL} ",
                    "size": 250059350016,
                    "type": "SSD",
                },
            ],
        )

        await self._machine.get_disks()

        self.assertEqual(len(self._machine.disks), 1)
        disk = self._machine.disks[0]
        self.assertEqual(disk.serial, SERIAL)
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)
class TestPool(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_dataset_data_interpretation(self) -> None:
        AVAILABLE_BYTES = 841462824960
        COMMENTS = "this is a comment"
        COMPRESSION_RATIO = 1.19
        DATASET_ID = "ssd0"
        POOL_NAME = "ssd0"
        USED_BYTES = 602317275136
        self._server.register_method_handler(
            "pool.dataset.query",
            lambda *args: [
                {
                    "available": {
                        "parsed": AVAILABLE_BYTES,
                        "rawvalue": str(AVAILABLE_BYTES),
                        "source": "NONE",
                        "value": "784G",
                    },
                    "comments": {
                        "parsed": COMMENTS,
                        "rawvalue": COMMENTS,
                        "source": "LOCAL",
                        "value": COMMENTS,
                    },
                    "compressratio": {
                        "parsed": str(COMPRESSION_RATIO),
                        "rawvalue": str(COMPRESSION_RATIO),
                        "source": "NONE",
                        "value": f"{COMPRESSION_RATIO}x",
                    },
                    "id": DATASET_ID,
                    "pool": POOL_NAME,
                    "type": "FILESYSTEM",
                    "used": {
                        "parsed": USED_BYTES,
                        "rawvalue": str(USED_BYTES),
                        "source": "NONE",
                        "value": "266G",
                    },
                },
            ],
        )

        await self._machine.get_datasets()

        self.assertEqual(len(self._machine.datasets), 1)
        dataset = self._machine.datasets[0]
        self.assertEqual(dataset.available_bytes, AVAILABLE_BYTES)
        assert dataset.comments
        self.assertEqual(dataset.comments.parsedValue, COMMENTS)
        self.assertEqual(dataset.comments.rawValue, COMMENTS)
        self.assertEqual(dataset.comments.source, DatasetPropertySource.LOCAL)
        self.assertEqual(dataset.comments.value, COMMENTS)
        self.assertEqual(dataset.compression_ratio, COMPRESSION_RATIO)
        self.assertEqual(dataset.id, DATASET_ID)
        self.assertEqual(dataset.pool_name, POOL_NAME)
        self.assertEqual(dataset.total_bytes, USED_BYTES + AVAILABLE_BYTES)
        self.assertEqual(dataset.type, DatasetType.FILESYSTEM)
        self.assertEqual(dataset.used_bytes, USED_BYTES)

    async def test_dataset_data_interpretation_no_comments(self) -> None:
        AVAILABLE_BYTES = 841462824960
        COMPRESSION_RATIO = 1.19
        DATASET_ID = "ssd0/myvol"
        POOL_NAME = "ssd0"
        USED_BYTES = 602317275136
        self._server.register_method_handler(
            "pool.dataset.query",
            lambda *args: [
                {
                    "available": {
                        "parsed": AVAILABLE_BYTES,
                        "rawvalue": str(AVAILABLE_BYTES),
                        "source": "NONE",
                        "value": "784G",
                    },
                    "compressratio": {
                        "parsed": str(COMPRESSION_RATIO),
                        "rawvalue": str(COMPRESSION_RATIO),
                        "source": "NONE",
                        "value": f"{COMPRESSION_RATIO}x",
                    },
                    "id": DATASET_ID,
                    "pool": POOL_NAME,
                    "type": "VOLUME",
                    "used": {
                        "parsed": USED_BYTES,
                        "rawvalue": str(USED_BYTES),
                        "source": "NONE",
                        "value": "266G",
                    },
                },
            ],
        )

        await self._machine.get_datasets()

        self.assertEqual(len(self._machine.datasets), 1)
        dataset = self._machine.datasets[0]
        self.assertEqual(dataset.available_bytes, AVAILABLE_BYTES)
        self.assertEqual(dataset.comments, None)
        self.assertEqual(dataset.compression_ratio, COMPRESSION_RATIO)
        self.assertEqual(dataset.id, DATASET_ID)
        self.assertEqual(dataset.pool_name, POOL_NAME)
        self.assertEqual(dataset.total_bytes, USED_BYTES + AVAILABLE_BYTES)
        self.assertEqual(dataset.type, DatasetType.VOLUME)
        self.assertEqual(dataset.used_bytes, USED_BYTES)

    async def test_availability(self) -> None:
        self._server.register_method_handler(
            "pool.dataset.query",
            lambda *args: [
                {
                    "available": {
                        "parsed": 841396957184,
                        "rawvalue": "841396957184",
                        "source": "NONE",
                        "value": "784G",
                    },
                    "compressratio": {
                        "parsed": "1.19",
                        "rawvalue": "1.19",
                        "source": "NONE",
                        "value": "1.19x",
                    },
                    "id": "ssd0/iscsi/sdwilsh-desktop",
                    "pool": "ssd0",
                    "type": "VOLUME",
                    "used": {
                        "parsed": 285263630336,
                        "rawvalue": "285263630336",
                        "source": "NONE",
                        "value": "266G",
                    },
                },
            ],
        )

        await self._machine.get_datasets()

        dataset = self._machine.datasets[0]
        self.assertTrue(dataset.available)

        self._server.register_method_handler(
            "pool.dataset.query",
            lambda *args: [],
            override=True,
        )
        await self._machine.get_datasets()
        self.assertFalse(dataset.available)
        self.assertEqual(len(self._machine.datasets), 0)

    async def test_unavailable_caching(self) -> None:
        """Certain properites have caching even if no longer available"""
        AVAILABLE_BYTES = 841462824960
        COMMENTS = "this is a comment"
        COMPRESSION_RATIO = 1.19
        DATASET_ID = "ssd0"
        POOL_NAME = "ssd0"
        USED_BYTES = 602317275136
        self._server.register_method_handler(
            "pool.dataset.query",
            lambda *args: [
                {
                    "available": {
                        "parsed": AVAILABLE_BYTES,
                        "rawvalue": str(AVAILABLE_BYTES),
                        "source": "NONE",
                        "value": "784G",
                    },
                    "comments": {
                        "parsed": COMMENTS,
                        "rawvalue": COMMENTS,
                        "source": "INHERITED",
                        "value": COMMENTS,
                    },
                    "compressratio": {
                        "parsed": str(COMPRESSION_RATIO),
                        "rawvalue": str(COMPRESSION_RATIO),
                        "source": "NONE",
                        "value": f"{COMPRESSION_RATIO}x",
                    },
                    "id": DATASET_ID,
                    "pool": POOL_NAME,
                    "type": "FILESYSTEM",
                    "used": {
                        "parsed": USED_BYTES,
                        "rawvalue": str(USED_BYTES),
                        "source": "NONE",
                        "value": "266G",
                    },
                },
            ],
        )

        await self._machine.get_datasets()
        dataset = self._machine.datasets[0]
        assert dataset is not None
        self._server.register_method_handler(
            "pool.dataset.query",
            lambda *args: [],
            override=True,
        )
        await self._machine.get_datasets()

        self.assertEqual(dataset.available_bytes, AVAILABLE_BYTES)
        assert dataset.comments
        self.assertEqual(dataset.comments.parsedValue, COMMENTS)
        self.assertEqual(dataset.comments.rawValue, COMMENTS)
        self.assertEqual(dataset.comments.source, DatasetPropertySource.INHERITED)
        self.assertEqual(dataset.comments.value, COMMENTS)
        self.assertEqual(dataset.compression_ratio, COMPRESSION_RATIO)
        self.assertEqual(dataset.id, DATASET_ID)
        self.assertEqual(dataset.pool_name, POOL_NAME)
        self.assertEqual(dataset.total_bytes, USED_BYTES + AVAILABLE_BYTES)
        self.assertEqual(dataset.type, DatasetType.FILESYSTEM)
        self.assertEqual(dataset.used_bytes, USED_BYTES)

    async def test_same_instance_after_get_datasets(self) -> None:
        self._server.register_method_handler(
            "pool.dataset.query",
            lambda *args: [
                {
                    "id": "ssd0",
                },
            ],
        )
        await self._machine.get_datasets()
        original_dataset = self._machine.datasets[0]
        await self._machine.get_datasets()
        new_dataset = self._machine.datasets[0]
        self.assertIs(original_dataset, new_dataset)

    def test_eq_impl(self) -> None:
        self._machine._dataset_fetcher._state = {  # type: ignore
            "ssd0": {
                "id": "ssd0",
            }
        }
        a = CachingDataset(self._machine._dataset_fetcher, "ssd0")  # type: ignore
        b = CachingDataset(self._machine._dataset_fetcher, "ssd0")  # type: ignore
        self.assertEqual(a, b)
Beispiel #8
0
class TestJob(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:
        JOB_ID = 42
        self._server.register_method_handler(
            "core.get_jobs",
            lambda *args: [
                {
                    "arguments": ["jail01"],
                    "error":
                    None,
                    "exc_info":
                    None,
                    "exception":
                    None,
                    "id":
                    JOB_ID,
                    "logs_excerpt":
                    None,
                    "logs_path":
                    None,
                    "method":
                    "jail.start",
                    "progress": {
                        "description": None,
                        "extra": None,
                        "percent": None
                    },
                    "result":
                    None,
                    "state":
                    "RUNNING",
                    "time_finished":
                    None,
                    "time_started":
                    datetime.datetime(2021,
                                      1,
                                      6,
                                      17,
                                      51,
                                      29,
                                      741000,
                                      tzinfo=datetime.timezone.utc),
                },
            ],
        )

        job = await self._machine.get_job(42)
        self.assertEqual(job.id, JOB_ID)
        self.assertEqual(job.method, "jail.start")
        self.assertEqual(job.status, JobStatus.RUNNING)

    async def test_success_data_interpretation(self) -> None:
        JOB_ID = 42
        self._server.register_method_handler(
            "core.get_jobs",
            lambda *args: [{
                "arguments": ["jail01"],
                "error":
                None,
                "exc_info":
                None,
                "exception":
                None,
                "id":
                JOB_ID,
                "logs_excerpt":
                None,
                "logs_path":
                None,
                "method":
                "jail.start",
                "progress": {
                    "description": None,
                    "extra": None,
                    "percent": 100
                },
                "result":
                True,
                "state":
                "SUCCESS",
                "time_finished":
                datetime.datetime(2021,
                                  1,
                                  6,
                                  17,
                                  51,
                                  41,
                                  281000,
                                  tzinfo=datetime.timezone.utc),
                "time_started":
                datetime.datetime(2021,
                                  1,
                                  6,
                                  17,
                                  51,
                                  29,
                                  741000,
                                  tzinfo=datetime.timezone.utc),
            }],
        )

        job = await self._machine.get_job(42)
        self.assertEqual(job.id, JOB_ID)
        self.assertEqual(job.method, "jail.start")
        self.assertEqual(job.result, True)
        self.assertEqual(job.status, JobStatus.SUCCESS)

    async def test_failed_data_interpretation(self) -> None:
        JOB_ID = 42
        self._server.register_method_handler(
            "core.get_jobs",
            lambda *args: [{
                "arguments": ["jail01"],
                "error":
                "[EFAULT] jail01 is not running",
                "exc_info": {
                    "extra": None,
                    "type": "CallError"
                },
                "exception":
                "Traceback (most recent call last):...",
                "id":
                JOB_ID,
                "logs_excerpt":
                None,
                "logs_path":
                None,
                "method":
                "jail.stop",
                "progress": {
                    "description": None,
                    "extra": None,
                    "percent": None
                },
                "result":
                None,
                "state":
                "FAILED",
                "time_finished":
                datetime.datetime(2021,
                                  1,
                                  6,
                                  5,
                                  22,
                                  38,
                                  286000,
                                  tzinfo=datetime.timezone.utc),
                "time_started":
                datetime.datetime(2021,
                                  1,
                                  6,
                                  5,
                                  22,
                                  37,
                                  945000,
                                  tzinfo=datetime.timezone.utc),
            }],
        )

        job = await self._machine.get_job(42)
        self.assertEqual(job.error, "[EFAULT] jail01 is not running")
        self.assertEqual(job.id, JOB_ID)
        self.assertEqual(job.method, "jail.stop")
        self.assertEqual(job.status, JobStatus.FAILED)

    async def test_waiting_data_interpretation(self) -> None:
        JOB_ID = 42
        self._server.register_method_handler(
            "core.get_jobs",
            lambda *args: [
                {
                    "arguments": ["jail01"],
                    "error":
                    None,
                    "exc_info":
                    None,
                    "exception":
                    None,
                    "id":
                    JOB_ID,
                    "logs_excerpt":
                    None,
                    "logs_path":
                    None,
                    "method":
                    "jail.stop",
                    "progress": {
                        "description": None,
                        "extra": None,
                        "percent": None
                    },
                    "result":
                    None,
                    "state":
                    "WAITING",
                    "time_finished":
                    None,
                    "time_started":
                    datetime.datetime(2021,
                                      1,
                                      6,
                                      18,
                                      8,
                                      38,
                                      561000,
                                      tzinfo=datetime.timezone.utc),
                },
            ],
        )

        job = await self._machine.get_job(42)
        self.assertEqual(job.id, JOB_ID)
        self.assertEqual(job.method, "jail.stop")
        self.assertEqual(job.status, JobStatus.WAITING)