fix: inherit PhoneDriver, and stop asserting a contract the driver rejected
Closes netork#117. A Yealink is a desk phone. It inherited AccessPointDriver because nothing better existed, and netOrk reads that role to populate its wireless page, its AP profile pickers and its SSID drift view — so a phone appeared in all three. napalm-device-types now has PhoneDriver. TYPE_LABEL comes from it, so the local override is gone. The two failing fingerprint tests were asserting the opposite of a deliberate decision. HTTP_FINGERPRINT carries "yealink" as a heavy but *not* mandatory rule, with the reason written next to it: some models answer / with a redirect to their API page, whose body says "yealink" nowhere, and a mandatory rule disqualifies the driver whenever its pattern is absent. Making it mandatory would rule out a real phone. The tests demanded it be mandatory, and the Cisco test then asserted `not all(...)` over an empty list, which is False. Both now check the property that actually protects against a false match: none of this driver's patterns appear on a Cisco page, so it contributes no score and never wins.
This commit is contained in:
Binary file not shown.
@@ -21,14 +21,13 @@ import requests
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
from napalm.base.exceptions import ConnectionClosedException, ConnectionException
|
||||
from napalm_device_types import AccessPointDriver, FingerprintRule
|
||||
from napalm_device_types import FingerprintRule, PhoneDriver
|
||||
from napalm_device_types.models import HealthMetricsDict
|
||||
|
||||
|
||||
class YealinkDriver(AccessPointDriver):
|
||||
class YealinkDriver(PhoneDriver):
|
||||
"""NAPALM driver for Yealink IP phones (T-series, W-series, CP-series, VP-series)."""
|
||||
|
||||
TYPE_LABEL = "Phone"
|
||||
VENDOR = "Yealink"
|
||||
DRIVER_NAME = "yealink"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
"""Fingerprint tests for YealinkDriver."""
|
||||
|
||||
from napalm_device_types import DeviceTypeDriver, FingerprintRule
|
||||
from napalm_device_types import DeviceTypeDriver, PhoneDriver, role_keys_of
|
||||
from napalm_yealink import YealinkDriver
|
||||
|
||||
|
||||
@@ -24,9 +24,18 @@ def test_snmp_oid_prefix():
|
||||
assert YealinkDriver.SNMP_OBJECT_ID_PREFIX == "1.3.6.1.4.1.37403"
|
||||
|
||||
|
||||
def test_http_fingerprint_mandatory_yealink():
|
||||
mandatory = [r for r in YealinkDriver.HTTP_FINGERPRINT if r.mandatory]
|
||||
assert any(r.pattern == "yealink" for r in mandatory)
|
||||
def test_yealink_pattern_is_decisive_but_not_mandatory():
|
||||
"""A mandatory rule disqualifies the driver whenever the pattern is absent.
|
||||
|
||||
Some Yealink models answer / with a redirect to their API page, whose body
|
||||
carries no "yealink" anywhere — making the rule mandatory would rule out a
|
||||
real Yealink phone. It carries decisive weight instead, so a page that does
|
||||
say "yealink" still wins by a wide margin.
|
||||
"""
|
||||
yealink_rules = [r for r in YealinkDriver.HTTP_FINGERPRINT if r.pattern == "yealink"]
|
||||
assert yealink_rules, "the vendor pattern must be present at all"
|
||||
assert all(not r.mandatory for r in yealink_rules)
|
||||
assert max(r.weight for r in yealink_rules) >= 10.0
|
||||
|
||||
|
||||
def test_fingerprint_matches_t58_title():
|
||||
@@ -36,8 +45,16 @@ def test_fingerprint_matches_t58_title():
|
||||
assert all(r.pattern in combined for r in mandatory)
|
||||
|
||||
|
||||
def test_fingerprint_does_not_match_cisco():
|
||||
"""Cisco-Seite enthält kein 'yealink' → mandatory Pattern fehlt."""
|
||||
def test_fingerprint_scores_nothing_on_a_cisco_page():
|
||||
"""Without a mandatory rule, what keeps a Cisco phone out is that none of
|
||||
Yealink's patterns match it at all — so the driver contributes zero score
|
||||
and never wins."""
|
||||
combined = "cisco ip phone cp-8841 "
|
||||
mandatory = [r for r in YealinkDriver.HTTP_FINGERPRINT if r.mandatory]
|
||||
assert not all(r.pattern in combined for r in mandatory)
|
||||
assert not any(r.pattern in combined for r in YealinkDriver.HTTP_FINGERPRINT)
|
||||
|
||||
|
||||
def test_declares_the_phone_role_not_access_point():
|
||||
"""A desk phone used to inherit AccessPointDriver for want of anywhere
|
||||
better, which put it in netOrk's wireless page and AP profile pickers."""
|
||||
assert issubclass(YealinkDriver, PhoneDriver)
|
||||
assert role_keys_of(YealinkDriver) == ["phone"]
|
||||
|
||||
Reference in New Issue
Block a user