Skip to content

Commit

Permalink
GatewayDescriptor parsing independent of DIB order (#981)
Browse files Browse the repository at this point in the history
  • Loading branch information
farmio authored Jun 22, 2022
1 parent a79c299 commit 109575a
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 5 deletions.
4 changes: 4 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ nav_order: 2

## Unreleased changes

### Bugfix

- Fix GatewayDescriptor parsing when SearchResponseExtended DIBs are in unexpected order

## 0.21.4 Fan out 2022-06-07

### Devices
Expand Down
138 changes: 138 additions & 0 deletions test/io_tests/gateway_scanner_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,148 @@
SearchRequest,
SearchRequestExtended,
SearchResponse,
SearchResponseExtended,
)
from xknx.telegram import IndividualAddress


class TestGatewayDescriptor:
"""Test GatewayDescriptor object."""

@pytest.mark.parametrize(
"raw,expected",
[
(
# MDT SCN-IP000.03 IP Interface (IP-Secure enabled)
bytes.fromhex(
"0610020c00a20801c0a800ba0e57360102001101000000837b40054500000000"
"cc1be080b80153434e2d49503030302e303320495020496e7465726661636520"
"6d6974200c02020203020402070209010808000000f000121003000000004005"
"45000000000001041404c0a800ba40054500c0a800010000000004000c051101"
"1102110311041105060603010401140700f01102000011030000110400001105"
"0000"
),
{
"supports_routing": False,
"supports_tunnelling": True,
"supports_tunnelling_tcp": True,
"supports_secure": True,
"routing_requires_secure": False,
"tunnelling_requires_secure": True,
},
),
(
# MDT SCN-IP100.02 IP Router (no IP-Secure support, CoreV1)
bytes.fromhex(
"06100202004e08010a0102280e5736010200200000000083477f0124e000170c"
"cc1be08004c44d4454204b4e5820495020526f75746572000000000000000000"
"000000000a020201030104010501"
),
{
"supports_routing": True,
"supports_tunnelling": True,
"supports_tunnelling_tcp": False,
"supports_secure": False,
"routing_requires_secure": None,
"tunnelling_requires_secure": None,
},
),
(
# Gira X1 (no IP-Secure support but CoreV2)
bytes.fromhex(
"0610020c006408010a0100290e57360102001001000000081171012600000000"
"000ab3290b134769726120583100000000000000000000000000000000000000"
"000000000c0202020302040207010901140700dc10fbfff810fcffff10fdffff"
"10feffff"
),
{
"supports_routing": False,
"supports_tunnelling": True,
"supports_tunnelling_tcp": True,
"supports_secure": True,
"routing_requires_secure": None,
"tunnelling_requires_secure": None,
},
),
(
# Gira IP-Router I12 (no IP-Secure support but CoreV2)
bytes.fromhex(
"0610020c006608010a0100280e57360102001000000000082d40834de000170c"
"000ab3274a3247697261204b4e582f49502d526f757465720000000000000000"
"000000000e02020203020402050207010901140700dc10f1fffe10f2ffff10f3"
"ffff10f4ffff"
),
{
"supports_routing": True,
"supports_tunnelling": True,
"supports_tunnelling_tcp": True,
"supports_secure": True,
"routing_requires_secure": None,
"tunnelling_requires_secure": None,
},
),
(
# Jung IPR 300 SREG (IP-Secure disabled)
bytes.fromhex(
"0610020c007408010a0101550e57360102004000000000a615000037e000170c"
"0022d10400374a756e67204b4e582049502d526f757465720000000000000000"
"000000000c0202020302040205020901240700f8400100054002000540030005"
"4004000540050005400600054007000540080005"
),
{
"supports_routing": True,
"supports_tunnelling": True,
"supports_tunnelling_tcp": True,
"supports_secure": True,
"routing_requires_secure": None,
"tunnelling_requires_secure": None,
},
),
(
# Jung IPR 300 SREG (IP-Secure enabled)
bytes.fromhex(
"0610020c008408010a0101550e57360102004000000000a615000037e000170c"
"0022d10400374b4e582049502d526f7574657200000000000000000000000000"
"000000000c02020203020402050209010808000004b0091a0806030104010501"
"240700f840010005400200054003000540040005400500054006000540070005"
"40080005"
),
{
"supports_routing": True,
"supports_tunnelling": True,
"supports_tunnelling_tcp": True,
"supports_secure": True,
"routing_requires_secure": True,
"tunnelling_requires_secure": True,
},
),
],
)
def test_parser(self, raw, expected):
"""Test parsing GatewayDescriptor objects from real-world responses."""
response = KNXIPFrame()
response.from_knx(raw)
assert isinstance(response.body, (SearchResponse, SearchResponseExtended))

descriptor = GatewayDescriptor(
ip_addr=response.body.control_endpoint.ip_addr,
port=response.body.control_endpoint.port,
)
descriptor.parse_dibs(response.body.dibs)

assert descriptor.supports_routing is expected["supports_routing"]
assert descriptor.supports_tunnelling is expected["supports_tunnelling"]
assert descriptor.supports_tunnelling_tcp is expected["supports_tunnelling_tcp"]

assert descriptor.supports_secure is expected["supports_secure"]

assert descriptor.routing_requires_secure is expected["routing_requires_secure"]
assert (
descriptor.tunnelling_requires_secure
is expected["tunnelling_requires_secure"]
)


class TestGatewayScanner:
"""Test class for xknx/io/GatewayScanner objects."""

Expand Down
20 changes: 15 additions & 5 deletions xknx/knxip/dib.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from abc import ABC, abstractmethod
import socket
from typing import NamedTuple
from typing import NamedTuple, final

from xknx.exceptions import CouldNotParseKNXIP
from xknx.telegram import IndividualAddress
Expand Down Expand Up @@ -117,6 +117,7 @@ def __repr__(self) -> str:
return f'<DIB dtc="{self.dtc}" data="{", ".join(f"0x{i:02x}" for i in self.data)}" />'


@final
class DIBDeviceInformation(DIB):
"""Class for serialization and deserialization of KNX DIB Device Information Block."""

Expand Down Expand Up @@ -213,10 +214,10 @@ def __repr__(self) -> str:
)


class DIBSuppSVCFamilies(DIB):
"""Class for serialization and deserialization of KNX DIB Supported Services."""
class _DIBServiceFamilies(DIB):
"""Base class for serialization and deserialization of KNX DIB Service Families."""

type_code = DIBTypeCode.SUPP_SVC_FAMILIES
type_code: DIBTypeCode

class Family:
"""Class for storing a supported device family."""
Expand Down Expand Up @@ -289,7 +290,15 @@ def __repr__(self) -> str:
return f'<{self.__class__.__name__} families="[{_families_str}]" />'


class DIBSecuredServiceFamilies(DIBSuppSVCFamilies):
@final
class DIBSuppSVCFamilies(_DIBServiceFamilies):
"""Class for serialization and deserialization of KNX DIB Supported Services."""

type_code = DIBTypeCode.SUPP_SVC_FAMILIES


@final
class DIBSecuredServiceFamilies(_DIBServiceFamilies):
"""Class for serialization and deserialization of KNX DIB Secured Service Families."""

type_code = DIBTypeCode.SECURED_SERVICE_FAMILIES
Expand All @@ -312,6 +321,7 @@ def __bytes__(self) -> bytes:
)


@final
class DIBTunnelingInfo(DIB):
"""Class for serialization and deserialization of KNX DIB Tunneling Info."""

Expand Down

0 comments on commit 109575a

Please sign in to comment.