async def _load_neighbors(self) -> None: async with self.execute(f"SELECT * FROM neighbors{DB_V}") as cursor: async for ieee, *fields in cursor: dev = self._application.get_device(ieee) neighbor = zdo_t.Neighbor(*fields) assert neighbor.is_valid dev.neighbors.add_neighbor(neighbor)
async def _migrate_to_v4(self): """Schema v4 expanded the node descriptor and neighbor table columns""" # The `node_descriptors` table was added in v1 if await self._table_exists("node_descriptors"): async with self.execute("SELECT * FROM node_descriptors") as cur: async for dev_ieee, value in cur: node_desc, rest = zdo_t.NodeDescriptor.deserialize(value) assert not rest await self.execute( "INSERT INTO node_descriptors_v4" " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (dev_ieee,) + node_desc.as_tuple(), ) # The `neighbors` table was added in v3 but the version number was not # incremented. It may not exist. if await self._table_exists("neighbors"): async with self.execute("SELECT * FROM neighbors") as cur: async for dev_ieee, epid, ieee, nwk, packed, prm, depth, lqi in cur: neighbor = zdo_t.Neighbor( extended_pan_id=epid, ieee=ieee, nwk=nwk, permit_joining=prm, depth=depth, lqi=lqi, reserved2=0b000000, **zdo_t.Neighbor._parse_packed(packed), ) await self.execute( "INSERT INTO neighbors_v4 VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", (dev_ieee,) + neighbor.as_tuple(), )
def test_neighbor(device): """Test neighbor struct.""" nei = zigpy.neighbor.Neighbor( zdo_t.Neighbor(device.ieee, device.ieee, 1, 2, 3, 4, 5), device) assert nei.device is device assert nei.neighbor.ieee == device.ieee
async def _load_neighbors(self) -> None: async with self.execute("SELECT * FROM neighbors") as cursor: async for (dev_ieee, epid, ieee, nwk, packed, prm, depth, lqi) in cursor: dev = self._application.get_device(dev_ieee) nei = zdo_t.Neighbor(epid, ieee, nwk, packed, prm, depth, lqi) dev.neighbors.add_neighbor(nei)
def test_neighbor_struct_relationship(): """Test neighbor packed struct relationship.""" for relationship in range(0, 7): struct = types.Neighbor() assert struct.relationship is None struct.relationship = relationship assert struct.relationship == relationship for i in range(0, 127): struct = types.Neighbor(packed=i) orig_dev_type = struct.device_type orig_rx = struct.rx_on_when_idle for relationship in range(0, 7): struct.relationship = relationship assert struct.device_type == orig_dev_type assert struct.rx_on_when_idle == orig_rx assert struct.relationship == relationship
def test_neighbor_struct_device_type(): """Test neighbor packed struct device_type.""" for dev_type in range(0, 3): struct = types.Neighbor() assert struct.device_type is None struct.device_type = dev_type assert struct.device_type == dev_type for i in range(0, 127): struct = types.Neighbor(packed=i) orig_rx = struct.rx_on_when_idle orig_rel = struct.relationship for dev_type in range(0, 3): struct.device_type = dev_type assert struct.rx_on_when_idle == orig_rx assert struct.relationship == orig_rel assert struct.device_type == dev_type
def test_neighbor_struct_rx_on_when_idle(): """Test neighbor packed struct rx_on_when_idle.""" for rx_on_when_idle in range(0, 3): struct = types.Neighbor() assert struct.rx_on_when_idle is None struct.rx_on_when_idle = rx_on_when_idle assert struct.rx_on_when_idle == rx_on_when_idle for i in range(0, 127): struct = types.Neighbor(**types.Neighbor._parse_packed(i)) orig_dev_type = struct.device_type orig_rel = struct.relationship for rx_on_when_idle in range(0, 3): struct.rx_on_when_idle = rx_on_when_idle assert struct.device_type == orig_dev_type assert struct.relationship == orig_rel assert struct.rx_on_when_idle == rx_on_when_idle
def test_bitstruct_complex(): data = (b"\x11\x00\xff\xee\xdd\xcc\xbb\xaa\x08\x07\x06" b"\x05\x04\x03\x02\x01\x00\x00\x24\x02\x00\x7c") neighbor, rest = zdo_t.Neighbor.deserialize(data + b"asd") assert rest == b"asd" neighbor2 = zdo_t.Neighbor( extended_pan_id=t.ExtendedPanId.convert("aa:bb:cc:dd:ee:ff:00:11"), ieee=t.EUI64.convert("01:02:03:04:05:06:07:08"), nwk=0x0000, device_type=zdo_t.Neighbor.DeviceType.Coordinator, rx_on_when_idle=zdo_t.Neighbor.RxOnWhenIdle.On, relationship=zdo_t.Neighbor.RelationShip.Sibling, reserved1=0b0, permit_joining=zdo_t.Neighbor.PermitJoins.Unknown, reserved2=0b000000, depth=0, lqi=124, ) assert neighbor == neighbor2 assert neighbor2.serialize() == data
async def test_migration_from_3_to_4(open_twice, test_db): test_db_v3 = test_db("simple_v3.sql") with sqlite3.connect(test_db_v3) as conn: cur = conn.cursor() neighbors_before = list(cur.execute("SELECT * FROM neighbors")) assert len(neighbors_before) == 2 assert all([len(row) == 8 for row in neighbors_before]) node_descs_before = list(cur.execute("SELECT * FROM node_descriptors")) assert len(node_descs_before) == 2 assert all([len(row) == 2 for row in node_descs_before]) # Ensure migration works on first run, and after shutdown if open_twice: app = await make_app(test_db_v3) await app.pre_shutdown() app = await make_app(test_db_v3) dev1 = app.get_device(nwk=0xBD4D) assert dev1.node_desc == zdo_t.NodeDescriptor( logical_type=zdo_t.LogicalType.Router, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=zdo_t.NodeDescriptor.FrequencyBand.Freq2400MHz, mac_capability_flags=142, manufacturer_code=4476, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=0, ) assert len(dev1.neighbors) == 1 assert dev1.neighbors[0].neighbor == zdo_t.Neighbor( extended_pan_id=t.ExtendedPanId.convert("81:b1:12:dc:9f:bd:f4:b6"), ieee=t.EUI64.convert("ec:1b:bd:ff:fe:54:4f:40"), nwk=0x6D1C, reserved1=0, device_type=zdo_t.Neighbor.DeviceType.Router, rx_on_when_idle=1, relationship=zdo_t.Neighbor.RelationShip.Sibling, reserved2=0, permit_joining=2, depth=15, lqi=130, ) dev2 = app.get_device(nwk=0x6D1C) assert dev2.node_desc == dev1.node_desc.replace(manufacturer_code=4456) assert len(dev2.neighbors) == 1 assert dev2.neighbors[0].neighbor == zdo_t.Neighbor( extended_pan_id=t.ExtendedPanId.convert("81:b1:12:dc:9f:bd:f4:b6"), ieee=t.EUI64.convert("00:0d:6f:ff:fe:a6:11:7a"), nwk=0xBD4D, reserved1=0, device_type=zdo_t.Neighbor.DeviceType.Router, rx_on_when_idle=1, relationship=zdo_t.Neighbor.RelationShip.Sibling, reserved2=0, permit_joining=2, depth=15, lqi=132, ) await app.pre_shutdown() with sqlite3.connect(test_db_v3) as conn: cur = conn.cursor() # Old tables are untouched assert neighbors_before == list(cur.execute("SELECT * FROM neighbors")) assert node_descs_before == list( cur.execute("SELECT * FROM node_descriptors")) # New tables exist neighbors_after = list(cur.execute("SELECT * FROM neighbors_v4")) assert len(neighbors_after) == 2 assert all([len(row) == 12 for row in neighbors_after]) node_descs_after = list( cur.execute("SELECT * FROM node_descriptors_v4")) assert len(node_descs_after) == 2 assert all([len(row) == 14 for row in node_descs_after])
async def test_neighbors(tmpdir): """Test neighbor loading.""" ext_pid = t.EUI64.convert("aa:bb:cc:dd:ee:ff:01:02") ieee_1 = make_ieee(1) nwk_1 = 0x1111 nei_1 = zdo_t.Neighbor(ext_pid, ieee_1, nwk_1, 2, 1, 1, 0, 0, 0, 15, 250) ieee_2 = make_ieee(2) nwk_2 = 0x2222 nei_2 = zdo_t.Neighbor(ext_pid, ieee_2, nwk_2, 1, 1, 2, 0, 0, 0, 15, 250) ieee_3 = make_ieee(3) nwk_3 = 0x3333 nei_3 = zdo_t.Neighbor(ext_pid, ieee_3, nwk_3, 1, 1, 2, 0, 0, 0, 15, 250) db = os.path.join(str(tmpdir), "test.db") app = await make_app(db) app.handle_join(nwk_1, ieee_1, 0) dev_1 = app.get_device(ieee_1) dev_1.node_desc = zdo_t.NodeDescriptor(2, 64, 128, 4174, 82, 82, 0, 82, 0) ep1 = dev_1.add_endpoint(1) ep1.status = zigpy.endpoint.Status.ZDO_INIT ep1.profile_id = 260 ep1.device_type = 0x1234 app.device_initialized(dev_1) # 2nd device app.handle_join(nwk_2, ieee_2, 0) dev_2 = app.get_device(ieee_2) dev_2.node_desc = zdo_t.NodeDescriptor(1, 64, 142, 4476, 82, 82, 0, 82, 0) ep2 = dev_2.add_endpoint(1) ep2.status = zigpy.endpoint.Status.ZDO_INIT ep2.profile_id = 260 ep2.device_type = 0x1234 app.device_initialized(dev_2) neighbors = zdo_t.Neighbors(2, 0, [nei_2, nei_3]) p1 = patch.object( dev_1.zdo, "request", new=AsyncMock(return_value=(zdo_t.Status.SUCCESS, neighbors)), ) with p1: res = await dev_1.neighbors.scan() assert res neighbors = zdo_t.Neighbors(2, 0, [nei_1, nei_3]) p1 = patch.object( dev_2.zdo, "request", new=AsyncMock(return_value=(zdo_t.Status.SUCCESS, neighbors)), ) with p1: res = await dev_2.neighbors.scan() assert res await app.pre_shutdown() del dev_1, dev_2 # Everything should've been saved - check that it re-loads app2 = await make_app(db) dev_1 = app2.get_device(ieee_1) dev_2 = app2.get_device(ieee_2) assert len(dev_1.neighbors) == 2 assert dev_1.neighbors[0].device is dev_2 assert dev_1.neighbors[1].device is None assert dev_1.neighbors[1].neighbor.ieee == ieee_3 assert len(dev_2.neighbors.neighbors) == 2 assert dev_2.neighbors[0].device is dev_1 assert dev_2.neighbors[1].device is None assert dev_2.neighbors[1].neighbor.ieee == ieee_3 await app2.pre_shutdown() os.unlink(db)
async def _load_neighbors(self): for (dev_ieee, epid, ieee, nwk, packed, prm, depth, lqi) in self._scan("neighbors"): dev = self._application.get_device(dev_ieee) nei = zdo_t.Neighbor(epid, ieee, nwk, packed, prm, depth, lqi) dev.neighbors.add_neighbor(nei)