mirror of
https://github.com/JoelBender/bacpypes
synced 2025-09-28 22:15:23 +08:00
412 lines
13 KiB
Python
412 lines
13 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Test Network Discovery
|
|
----------------------
|
|
|
|
The TD is an application on network 1 with sniffer1, network 2 has an
|
|
application node and sniffer2. Both networks are connected to one IUT router.
|
|
"""
|
|
|
|
import unittest
|
|
|
|
from bacpypes.debugging import bacpypes_debugging, ModuleLogger, btox, xtob
|
|
|
|
from bacpypes.comm import Client, Server, bind
|
|
from bacpypes.pdu import (
|
|
PDU, Address, LocalBroadcast,
|
|
RemoteStation, RemoteBroadcast,GlobalBroadcast,
|
|
)
|
|
from bacpypes.vlan import Network
|
|
|
|
from bacpypes.npdu import (
|
|
npdu_types, NPDU,
|
|
WhoIsRouterToNetwork, IAmRouterToNetwork, ICouldBeRouterToNetwork,
|
|
RejectMessageToNetwork, RouterBusyToNetwork, RouterAvailableToNetwork,
|
|
RoutingTableEntry, InitializeRoutingTable, InitializeRoutingTableAck,
|
|
EstablishConnectionToNetwork, DisconnectConnectionToNetwork,
|
|
WhatIsNetworkNumber, NetworkNumberIs,
|
|
)
|
|
from bacpypes.apdu import (
|
|
WhoIsRequest, IAmRequest,
|
|
ReadPropertyRequest, ReadPropertyACK,
|
|
AbortPDU,
|
|
)
|
|
|
|
from ..state_machine import match_pdu, StateMachineGroup
|
|
from ..time_machine import reset_time_machine, run_time_machine, current_time
|
|
|
|
from .helpers import (
|
|
SnifferStateMachine, NetworkLayerStateMachine, RouterNode, ApplicationLayerStateMachine,
|
|
ApplicationNode,
|
|
)
|
|
|
|
# some debugging
|
|
_debug = 0
|
|
_log = ModuleLogger(globals())
|
|
|
|
|
|
#
|
|
# TNetwork
|
|
#
|
|
|
|
@bacpypes_debugging
|
|
class TNetwork(StateMachineGroup):
|
|
|
|
def __init__(self):
|
|
if _debug: TNetwork._debug("__init__")
|
|
StateMachineGroup.__init__(self)
|
|
|
|
# reset the time machine
|
|
reset_time_machine()
|
|
if _debug: TNetwork._debug(" - time machine reset")
|
|
|
|
# implementation under test
|
|
self.iut = RouterNode()
|
|
|
|
# make a little LAN
|
|
self.vlan1 = Network(name="vlan1", broadcast_address=LocalBroadcast())
|
|
|
|
# test device
|
|
self.td = ApplicationLayerStateMachine("1", self.vlan1)
|
|
self.append(self.td)
|
|
|
|
# sniffer node
|
|
self.sniffer1 = SnifferStateMachine("2", self.vlan1)
|
|
self.append(self.sniffer1)
|
|
|
|
# add the network
|
|
self.iut.add_network("3", self.vlan1, 1)
|
|
|
|
# make another little LAN
|
|
self.vlan2 = Network(name="vlan3", broadcast_address=LocalBroadcast())
|
|
|
|
# application node, not a state machine
|
|
self.app2 = ApplicationNode("4", self.vlan2)
|
|
|
|
# sniffer node
|
|
self.sniffer2 = SnifferStateMachine("5", self.vlan2)
|
|
self.append(self.sniffer2)
|
|
|
|
# add the network
|
|
self.iut.add_network("6", self.vlan2, 2)
|
|
|
|
def run(self, time_limit=60.0):
|
|
if _debug: TNetwork._debug("run %r", time_limit)
|
|
if _debug: TNetwork._debug(" - current_time: %r", current_time())
|
|
|
|
# run the group
|
|
super(TNetwork, self).run()
|
|
if _debug: TNetwork._debug(" - current_time: %r", current_time())
|
|
|
|
# run it for some time
|
|
run_time_machine(time_limit)
|
|
if _debug: TNetwork._debug(" - current_time: %r", current_time())
|
|
|
|
if _debug:
|
|
TNetwork._debug(" - time machine finished")
|
|
for state_machine in self.state_machines:
|
|
TNetwork._debug(" - machine: %r", state_machine)
|
|
for direction, pdu in state_machine.transaction_log:
|
|
TNetwork._debug(" %s %s", direction, str(pdu))
|
|
|
|
# check for success
|
|
all_success, some_failed = super(TNetwork, self).check_for_success()
|
|
assert all_success
|
|
|
|
|
|
@bacpypes_debugging
|
|
class TestSimple(unittest.TestCase):
|
|
|
|
def test_idle(self):
|
|
"""Test an idle network, nothing happens is success."""
|
|
if _debug: TestSimple._debug("test_idle")
|
|
|
|
# create a network
|
|
tnet = TNetwork()
|
|
|
|
# all start states are successful
|
|
tnet.td.start_state.success()
|
|
tnet.sniffer1.start_state.success()
|
|
tnet.sniffer2.start_state.success()
|
|
|
|
# run the group
|
|
tnet.run()
|
|
|
|
|
|
@bacpypes_debugging
|
|
class TestUnconfirmedRequests(unittest.TestCase):
|
|
|
|
def test_local_broadcast(self):
|
|
"""Local broadcast, no matching device."""
|
|
if _debug: TestUnconfirmedRequests._debug("test_local_broadcast")
|
|
|
|
# create a network
|
|
tnet = TNetwork()
|
|
|
|
# test device sends request, no response
|
|
tnet.td.start_state.doc("1-1-0") \
|
|
.send(WhoIsRequest(
|
|
destination=LocalBroadcast(),
|
|
)).doc("1-1-1") \
|
|
.timeout(3).doc("1-1-2") \
|
|
.success()
|
|
|
|
# sniffer on network 1 sees the request and nothing else
|
|
tnet.sniffer1.start_state.doc("1-2-0") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.00' # version, application layer
|
|
'10 08' # unconfirmed Who-Is
|
|
)
|
|
).doc("1-2-1") \
|
|
.timeout(3).doc("1-2-2") \
|
|
.success()
|
|
|
|
# no acitivity on network 2
|
|
tnet.sniffer2.start_state.success()
|
|
|
|
# run the group
|
|
tnet.run()
|
|
|
|
def test_remote_broadcast_2(self):
|
|
"""Remote broadcast, matching device."""
|
|
if _debug: TestUnconfirmedRequests._debug("test_remote_broadcast_2")
|
|
|
|
# create a network
|
|
tnet = TNetwork()
|
|
|
|
# test device sends request and sees the response
|
|
tnet.td.start_state.doc("2-1-0") \
|
|
.send(WhoIsRequest(
|
|
destination=RemoteBroadcast(2),
|
|
)).doc("2-1-1") \
|
|
.success()
|
|
|
|
# sniffer on network 1 sees the request and the response
|
|
tnet.sniffer1.start_state.doc("2-2-0") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.80.00.00.02' # who is router to network
|
|
)
|
|
).doc("2-2-1") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.80.01.00.02' # I am router to network
|
|
)
|
|
).doc("2-2-1") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.20.00.02.00.ff' # remote broadcast goes out
|
|
'10.08'
|
|
)
|
|
).doc("2-2-1") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.08.00.02.01.04' # unicast response
|
|
'10.00.c4.02.00.00.04.22.04.00.91.00.22.03.e7'
|
|
)
|
|
).doc("2-2-2") \
|
|
.timeout(3).doc("2-2-3") \
|
|
.success()
|
|
|
|
# network 2 sees local broadcast request and unicast response
|
|
tnet.sniffer2.start_state.doc('2-3-0') \
|
|
.receive(PDU,
|
|
pduData=xtob('01.08.00.01.01.01' # local broadcast
|
|
'10.08'
|
|
)
|
|
).doc("2-3-1") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.20.00.01.01.01.ff' # unicast response
|
|
'10.00.c4.02.00.00.04.22.04.00.91.00.22.03.e7'
|
|
)
|
|
).doc("2-3-1") \
|
|
.timeout(3).doc("2-3-2") \
|
|
.success()
|
|
|
|
# run the group
|
|
tnet.run()
|
|
|
|
def test_remote_broadcast_3(self):
|
|
"""Remote broadcast, nonexistent network."""
|
|
if _debug: TestUnconfirmedRequests._debug("test_remote_broadcast_3")
|
|
|
|
# create a network
|
|
tnet = TNetwork()
|
|
|
|
# test device sends request and sees the response
|
|
tnet.td.start_state.doc("3-1-0") \
|
|
.send(WhoIsRequest(
|
|
destination=RemoteBroadcast(3),
|
|
)).doc("3-1-1") \
|
|
.success()
|
|
|
|
# sniffer on network 1 sees the request and the response
|
|
tnet.sniffer1.start_state.doc("3-2-0") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.80.00.00.03' # who is router to network
|
|
)
|
|
).doc("3-2-1") \
|
|
.timeout(3).doc("3-2-3") \
|
|
.success()
|
|
|
|
# network 2 sees local broadcast looking for network 3
|
|
tnet.sniffer2.start_state.doc('3-3-0') \
|
|
.receive(PDU,
|
|
pduData=xtob('01.88.00.01.01.01.00.00.03'
|
|
)
|
|
).doc("3-3-1") \
|
|
.timeout(3).doc("3-3-2") \
|
|
.success()
|
|
|
|
# run the group
|
|
tnet.run()
|
|
|
|
def test_global_broadcast(self):
|
|
"""Global broadcast, matching device."""
|
|
if _debug: TestUnconfirmedRequests._debug("test_global_broadcast")
|
|
|
|
# create a network
|
|
tnet = TNetwork()
|
|
|
|
# test device sends request and sees the response
|
|
tnet.td.start_state.doc("4-1-0") \
|
|
.send(WhoIsRequest(
|
|
destination=GlobalBroadcast(),
|
|
)).doc("4-1-1") \
|
|
.receive(IAmRequest).doc("4-1-2") \
|
|
.success()
|
|
|
|
# sniffer on network 1 sees the request and the response
|
|
tnet.sniffer1.start_state.doc("4-2-0") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.20.ff.ff.00.ff'
|
|
'10.08'
|
|
)
|
|
).doc("4-2-1") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.08.00.02.01.04'
|
|
'10.00.c4.02.00.00.04.22.04.00.91.00.22.03.e7'
|
|
)
|
|
).doc("4-2-2") \
|
|
.timeout(3).doc("4-2-3") \
|
|
.success()
|
|
|
|
# network 2 sees local broadcast request and unicast response
|
|
tnet.sniffer2.start_state.doc('4-3-0') \
|
|
.receive(PDU,
|
|
pduData=xtob('01.28.ff.ff.00.00.01.01.01.fe'
|
|
'10.08'
|
|
)
|
|
).doc("4-3-1") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.20.00.01.01.01.ff'
|
|
'10.00.c4.02.00.00.04.22.04.00.91.00.22.03.e7'
|
|
)
|
|
).doc("4-3-3") \
|
|
.timeout(3).doc("4-3-3") \
|
|
.success()
|
|
|
|
# run the group
|
|
tnet.run()
|
|
|
|
|
|
@bacpypes_debugging
|
|
class TestConfirmedRequests(unittest.TestCase):
|
|
|
|
def test_remote_read_2(self):
|
|
"""Remote read property, matching device."""
|
|
if _debug: TestConfirmedRequests._debug("test_remote_read_2")
|
|
|
|
# create a network
|
|
tnet = TNetwork()
|
|
|
|
# test device sends request and sees the response
|
|
tnet.td.start_state.doc("5-1-0") \
|
|
.send(ReadPropertyRequest(
|
|
destination=RemoteStation(2, 4),
|
|
objectIdentifier=('device', 4),
|
|
propertyIdentifier='vendorIdentifier',
|
|
)).doc("5-1-1") \
|
|
.receive(ReadPropertyACK).doc("5-1-2") \
|
|
.success()
|
|
|
|
# sniffer on network 1 sees the request and the response
|
|
tnet.sniffer1.start_state.doc("5-2-0") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.80.00.00.02' # who is router to network
|
|
)
|
|
).doc("5-2-1") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.80.01.00.02' # I am router to network
|
|
)
|
|
).doc("5-2-2") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.24.00.02.01.04.ff' # request
|
|
'02.44.01.0c.0c.02.00.00.04.19.78'
|
|
)
|
|
).doc("5-2-3") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.08.00.02.01.04' # ack
|
|
'30.01.0c.0c.02.00.00.04.19.78.3e.22.03.e7.3f'
|
|
)
|
|
).doc("5-2-4") \
|
|
.timeout(3).doc("5-2-5") \
|
|
.success()
|
|
|
|
# network 2 sees routed request and unicast response
|
|
tnet.sniffer2.start_state.doc('5-3-0') \
|
|
.receive(PDU,
|
|
pduData=xtob('01.0c.00.01.01.01' # request
|
|
'02.44.01.0c.0c.02.00.00.04.19.78'
|
|
)
|
|
).doc("5-3-1") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.20.00.01.01.01.ff' # ack
|
|
'30.01.0c.0c.02.00.00.04.19.78.3e.22.03.e7.3f'
|
|
)
|
|
).doc("5-3-2") \
|
|
.timeout(3).doc("5-3-3") \
|
|
.success()
|
|
|
|
# run the group
|
|
tnet.run()
|
|
|
|
def test_remote_read_3(self):
|
|
"""Remote read property, nonexistent device."""
|
|
if _debug: TestConfirmedRequests._debug("test_remote_read_3")
|
|
|
|
# create a network
|
|
tnet = TNetwork()
|
|
|
|
# test device sends request and sees the response
|
|
tnet.td.start_state.doc("6-1-0") \
|
|
.send(ReadPropertyRequest(
|
|
destination=RemoteStation(3, 5),
|
|
objectIdentifier=('device', 5),
|
|
propertyIdentifier='vendorIdentifier',
|
|
)).doc("6-1-1") \
|
|
.receive(AbortPDU,
|
|
apduAbortRejectReason=65,
|
|
).doc("6-1-2") \
|
|
.success()
|
|
|
|
# sniffer on network 1 sees the request for a path
|
|
tnet.sniffer1.start_state.doc("6-2-0") \
|
|
.receive(PDU,
|
|
pduData=xtob('01.80.00.00.03' # who is router to network
|
|
)
|
|
).doc("6-2-1") \
|
|
.timeout(3).doc("6-2-2") \
|
|
.success()
|
|
|
|
# network 2 sees local broadcast looking for network 3
|
|
tnet.sniffer2.start_state.doc('6-3-0') \
|
|
.receive(PDU,
|
|
pduData=xtob('01.88.00.01.01.01.00.00.03'
|
|
)
|
|
).doc("6-3-1") \
|
|
.timeout(3).doc("6-3-2") \
|
|
.success()
|
|
|
|
# run the group
|
|
tnet.run()
|
|
|