def test_network_switch_routes_packets_from_user_to_remote_destinations(): """Validate packets from source to known destination are properly served. In this test we define a model with `NetworkService` (mock'ed), `NetworkSwitch` (being tested) and two network interfaces - eth and wifi (both mock'ed). `NetworkSwitch` defines two routes via these interfaces. Then we generate a couple of packets for the destination known to the switch and imitate they being received by the switch in `handle_message`. We make sure that these packets are being filled with source, sender and received addresses (taken from the switching table), SSNs are assigned and the packets are transmitted to the proper network interfaces. """ sim, ns, eth, wifi = Mock(), Mock(), Mock(), Mock() switch = NetworkSwitch(sim) eth.address = 4 eth_conn = Mock() eth.connections.set = Mock(return_value=eth_conn) wifi.address = 8 wifi_conn = Mock() wifi.connections.set = Mock(return_value=wifi_conn) user_conn = switch.connections.set('user', ns, reverse=False) switch.connections.set('eth', eth, rname='network') switch.connections.set('wifi', wifi, rname='network') switch.table.add(10, connection='eth', next_hop=5) switch.table.add(20, connection='wifi', next_hop=13) pkt_1 = NetworkPacket(destination_address=10) pkt_2 = NetworkPacket(destination_address=20) switch.handle_message(pkt_1, connection=user_conn, sender=ns) sim.schedule.assert_called_with(0, eth.handle_message, args=(pkt_1, ), kwargs={ 'connection': eth_conn, 'sender': switch, }) assert pkt_1.receiver_address == 5 # = table[10].next_hop assert pkt_1.sender_address == 4 # = eth.address assert pkt_1.originator_address == 4 # = eth.address assert pkt_1.osn >= 0 # any value, but not None switch.handle_message(pkt_2, connection=user_conn, sender=ns) sim.schedule.assert_called_with(0, wifi.handle_message, args=(pkt_2, ), kwargs={ 'connection': wifi_conn, 'sender': switch, }) assert pkt_2.receiver_address == 13 # = table[20].next_hop assert pkt_2.sender_address == 8 # = wifi.address assert pkt_2.originator_address == 8 # = wifi.address assert pkt_2.osn >= 0 # = any value, but not None
def test_wire_frame_implements_str(): pkt_1 = NetworkPacket(data=AppData(100)) pkt_2 = NetworkPacket(data=AppData(200)) frame_1 = WireFrame(pkt_1, header_size=10, preamble=1, duration=2) assert str(frame_1) == f'WireFrame[D=2,HDR=10,PR=1 | {pkt_1}]' frame_2 = WireFrame(pkt_2) assert str(frame_2) == f'WireFrame[D=0,HDR=0,PR=0 | {pkt_2}]'
def test_network_packet_size(): data = MagicMock() data.size = 100 pkt1 = NetworkPacket(data=data) pkt2 = NetworkPacket() assert pkt1.size == 100 assert pkt2.size == 0
def test_network_switch_ignores_old_messages(): """Validate `NetworkSwitch` ignores messages with old SSN. """ sim, ns, iface = Mock(), Mock(), Mock() switch = NetworkSwitch(sim) iface.address = 1 iface_rev_conn = Mock() iface.connections.set = Mock(return_value=iface_rev_conn) ns_rev_conn = Mock() ns.connections.set = Mock(return_value=ns_rev_conn) switch.connections.set('user', ns, rname='network') iface_conn = switch.connections.set('iface', iface, rname='network') switch.table.add(10, connection='iface', next_hop=2) pkt_1 = NetworkPacket(destination_address=10, originator_address=13, osn=8) pkt_2 = NetworkPacket(destination_address=10, originator_address=13, osn=8) # the same SSN pkt_3 = NetworkPacket(destination_address=1, originator_address=13, osn=5) # older SSN, to sink pkt_4 = NetworkPacket(destination_address=1, originator_address=13, osn=9) # New one! pkt_5 = NetworkPacket(destination_address=10, originator_address=13, osn=8) # again old one switch.handle_message(pkt_1, connection=iface_conn, sender=iface) sim.schedule.assert_called_once_with(0, iface.handle_message, args=(pkt_1, ), kwargs={ 'connection': iface_rev_conn, 'sender': switch, }) sim.schedule.reset_mock() switch.handle_message(pkt_2, connection=iface_conn, sender=iface) sim.schedule.assert_not_called() switch.handle_message(pkt_3, connection=iface_conn, sender=iface) sim.schedule.assert_not_called() switch.handle_message(pkt_4, connection=iface_conn, sender=iface) sim.schedule.assert_called_once_with(0, ns.handle_message, args=(pkt_4, ), kwargs={ 'connection': ns_rev_conn, 'sender': switch, }) sim.schedule.reset_mock() switch.handle_message(pkt_5, connection=iface_conn, sender=iface) sim.schedule.assert_not_called()
def test_network_switch_sends_packets_with_its_interface_address_to_user(): """Validate packet with destination matching one interface is routed up. We send three packets: one from 'eth', one from 'wifi' and one from 'user'. Make sure that in any case the packet is routed to user. """ sim, ns, wifi, eth = Mock(), Mock(), Mock(), Mock() switch = NetworkSwitch(sim) ns_rev_conn = Mock() ns.connections.set = Mock(return_value=ns_rev_conn) eth.address = 1 wifi.address = 2 ns_conn = switch.connections.set('user', ns, rname='network') eth_conn = switch.connections.set('eth', eth, rname='network') wifi_conn = switch.connections.set('wifi', wifi, rname='network') pkt_1 = NetworkPacket(destination_address=2) pkt_2 = NetworkPacket(destination_address=2) pkt_3 = NetworkPacket(destination_address=2) # Sending the first packet from Ethernet interface: switch.handle_message(pkt_1, connection=eth_conn, sender=eth) sim.schedule.assert_called_once_with(0, ns.handle_message, args=(pkt_1, ), kwargs={ 'connection': ns_rev_conn, 'sender': switch, }) sim.schedule.reset_mock() # Sending another packet like from WiFi interface: switch.handle_message(pkt_2, connection=wifi_conn, sender=wifi) sim.schedule.assert_called_once_with(0, ns.handle_message, args=(pkt_2, ), kwargs={ 'connection': ns_rev_conn, 'sender': switch, }) sim.schedule.reset_mock() # Finally, send a packet from NetworkService (loopback-like behaviour): switch.handle_message(pkt_3, connection=ns_conn, sender=ns) sim.schedule.assert_called_once_with(0, ns.handle_message, args=(pkt_3, ), kwargs={ 'connection': ns_rev_conn, 'sender': switch, }) sim.schedule.reset_mock()
def test_network_packet_implements_str(): data = MagicMock() data.__str__.return_value = 'AppData{sid=13}' pkt1 = NetworkPacket(destination_address=10, originator_address=2, sender_address=5, receiver_address=6, osn=4, data=data) pkt2 = NetworkPacket(destination_address=5, data=data) pkt3 = NetworkPacket(destination_address=8) assert str(pkt1) == f'NetPkt{{DST=10,ORIGIN=2,SND=5,RCV=6,OSN=4 | {data}}}' assert str(pkt2) == f'NetPkt{{DST=5 | {data}}}' assert str(pkt3) == f'NetPkt{{DST=8}}'
def test_wired_transceiver_raises_error_if_requested_tx_during_another_tx(): sim, peer, queue = Mock(), Mock(), Mock() iface = WiredTransceiver(sim, bitrate=100) queue_conn = iface.connections.set('queue', queue, rname='iface') iface.connections.set('peer', peer, rname='peer') pkt_1 = NetworkPacket(data=AppData(size=10)) pkt_2 = NetworkPacket(data=AppData(size=20)) sim.stime = 0 iface.start() iface.handle_message(pkt_1, sender=queue, connection=queue_conn) with pytest.raises(RuntimeError): iface.handle_message(pkt_2, sender=queue, connection=queue_conn)
def test_pop_extracts_packets_in_correct_order(): sim = Mock() sim.stime = 0 data_size = [123, 412] packets = [NetworkPacket(data=AppData(0, sz, 0, 0)) for sz in data_size] queue = Queue(sim, capacity=2) queue.push(packets[0]) queue.push(packets[1]) assert queue.pop() == packets[0] assert not queue.empty() assert not queue.full() assert len(queue) == 1 assert queue.size() == 1 assert queue.bitsize() == data_size[1] assert tuple(qp.packet for qp in queue.as_tuple()) == (packets[1], ) assert queue.pop() == packets[1] assert queue.empty() assert not queue.full() assert len(queue) == 0 assert queue.size() == 0 assert queue.bitsize() == 0 assert queue.as_tuple() == ()
def test_finite_queue_without_service_writes_statistics(): sim = Mock() size = [123, 412, 230, 312] t0, t1, t2, t3, t4, t5 = 2, 7, 8, 10, 14, 19 packets = [NetworkPacket(data=AppData(0, sz, 0, 0)) for sz in size] sim.stime = t0 q = Queue(sim, capacity=2) # Run a sequence of operations: sim.stime = t1 q.push(packets[0]) # stored after: packet[0] sim.stime = t2 q.push(packets[1]) # stored after: packet[0], packet[1] sim.stime = t3 q.push(packets[2]) # dropped due to overflow, stored: packet[0], packet[1] sim.stime = t4 q.pop() # stored after: packet[1] sim.stime = t5 q.push(packets[3]) # stored after: packet[1], packet[3] assert tuple(qp.packet for qp in q.as_tuple()) == (packets[1], packets[3]) assert q.size_trace.as_tuple() == ((t0, 0), (t1, 1), (t2, 2), (t4, 1), (t5, 2)) assert q.bitsize_trace.as_tuple() == ( (t0, 0), (t1, size[0]), (t2, size[0] + size[1]), (t4, size[1]), (t5, size[1] + size[3]), ) assert q.num_dropped == 1
def test_wired_transceiver_sends_data_up_when_rx_completed(): sim, sender, switch = Mock(), Mock(), Mock() sim.stime = 0 iface = WiredTransceiver(sim) sim.schedule.reset_mock() # clear sim.schedule(0, iface.start) call pkt = NetworkPacket(data=AppData(size=100)) frame = WireFrame(pkt, duration=0.5, header_size=20, preamble=0.01) switch_rev_conn = Mock() switch.connections.set = Mock(return_value=switch_rev_conn) iface.connections.set('up', switch, rname='iface') sender_conn = iface.connections.set('peer', sender, rname='peer') assert iface.rx_ready and not iface.rx_busy iface.handle_message(frame, sender=sender, connection=sender_conn) assert not iface.rx_ready and iface.rx_busy sim.schedule.assert_called_once_with( frame.duration, iface.handle_rx_end, args=(frame, ), ) sim.schedule.reset_mock() sim.stime += frame.duration iface.handle_rx_end(frame) sim.schedule.assert_called_once_with(0, switch.handle_message, args=(pkt, ), kwargs={ 'sender': iface, 'connection': switch_rev_conn, }) assert iface.rx_ready and not iface.rx_busy
def test_saturated_queue_not_requests_source_when_not_empty_after_get_next(): sim, source, switch, service = Mock(), Mock(), Mock(), Mock() sim.stime = 0 service_rev_conn = Mock() service.connections.set = Mock(return_value=service_rev_conn) queue = SaturatedQueue(sim=sim, source=source) queue.connections.set('output', service, rname='queue') queue.connections.set('input', switch, reverse=False) pkt = NetworkPacket(data=AppData(size=100)) queue.push(pkt) assert queue.size() == 1 queue.get_next(service) # Validate that packet was passed to the service, but source.get_next() # not called: sim.schedule.assert_called_once_with(0, service.handle_message, args=(pkt, ), kwargs={ 'connection': service_rev_conn, 'sender': queue, }) source.get_next.assert_not_called() # However, after the queue became empty, it will call source: queue.get_next(service) source.get_next.assert_called_once()
def test_saturated_queue_requests_source_packet_when_empty_after_get_next(): sim, source, switch, service = Mock(), Mock(), Mock(), Mock() sim.stime = 0 service_rev_conn = Mock() service.connections.set = Mock(return_value=service_rev_conn) queue = SaturatedQueue(sim=sim, source=source) queue.connections.set('output', service, rname='queue') queue.connections.set('input', switch, reverse=False) # Requesting the next packet from the queue: queue.get_next(service) source.get_next.assert_called_once() # Assume that packet was generated by source, went through all layers # and arrived from the switch. Make sure that this packet will be # delivered to the service: pkt = NetworkPacket(data=AppData(size=100)) queue.handle_message(pkt) sim.schedule.assert_called_once_with(0, service.handle_message, args=(pkt, ), kwargs={ 'connection': service_rev_conn, 'sender': queue, })
def test_queue_with_service_passes_new_packet_directly_after_get_next_call(): sim, service = Mock(), Mock() sim.stime = 0 service_rev_conn = Mock() service.connections.set = Mock(return_value=service_rev_conn) queue = Queue(sim=sim) queue.connections.set('service', service, rname='queue') queue.get_next(service=service) packet = NetworkPacket(data=AppData(size=100)) sim.stime = 13 queue.push(packet) # Check that the message was delivered to the service: sim.schedule.assert_called_once_with(0, service.handle_message, args=(packet, ), kwargs={ 'connection': service_rev_conn, 'sender': queue, }) # Check that queue is still empty: assert queue.as_tuple() == () # Also make sure that size updates were not written: assert queue.size_trace.as_tuple() == ((0, 0), ) assert queue.bitsize_trace.as_tuple() == ((0, 0), ) assert queue.num_dropped == 0
def test_wire_frame_init_and_properties(): pkt_1 = NetworkPacket(data=AppData(100)) pkt_2 = NetworkPacket(data=AppData(200)) frame_1 = WireFrame(pkt_1, header_size=10, preamble=0.2, duration=1.5) assert frame_1.packet == pkt_1 assert frame_1.duration == 1.5 assert frame_1.header_size == 10 assert frame_1.preamble == 0.2 assert frame_1.size == 10 + pkt_1.size frame_2 = WireFrame(packet=pkt_2) assert frame_2.packet == pkt_2 assert frame_2.duration == 0 assert frame_2.header_size == 0 assert frame_2.preamble == 0 assert frame_2.size == 0
def test_network_switch_forwards_packets_received_from_network_interfaces(): """Validate packet with destination matching one interface is routed up. We send three packets: one from 'eth', one from 'wifi' and one from 'user'. Make sure that in any case the packet is routed to user. """ sim, ns, wifi, eth = Mock(), Mock(), Mock(), Mock() switch = NetworkSwitch(sim) eth.address = 1 eth_rev_conn = Mock() eth.connections.set = Mock(return_value=eth_rev_conn) wifi.address = 20 wifi_rev_conn = Mock() wifi.connections.set = Mock(return_value=wifi_rev_conn) switch.connections.set('user', ns, reverse=False) switch.connections.set('eth', eth, rname='network') wifi_conn = switch.connections.set('wifi', wifi, rname='network') switch.table.add(10, connection='eth', next_hop=2) switch.table.add(30, connection='wifi', next_hop=23) pkt_1 = NetworkPacket(destination_address=10, originator_address=5, osn=8) pkt_2 = NetworkPacket(destination_address=30, originator_address=17, osn=4) switch.handle_message(pkt_1, connection=wifi, sender=wifi_conn) sim.schedule.assert_called_once_with(0, eth.handle_message, args=(pkt_1, ), kwargs={ 'connection': eth_rev_conn, 'sender': switch, }) sim.schedule.reset_mock() switch.handle_message(pkt_2, connection=wifi, sender=wifi_conn) sim.schedule.assert_called_once_with(0, wifi.handle_message, args=(pkt_2, ), kwargs={ 'connection': wifi_rev_conn, 'sender': switch, })
def test_queue_accepts_packets_on_handle_message_call(): sim, producer = Mock(), Mock() sim.stime = 0 queue = Queue(sim=sim) conn = queue.connections.set('input', producer, reverse=False) pkt = NetworkPacket(data=AppData(size=123)) queue.handle_message(pkt, sender=producer, connection=conn) assert tuple(qp.packet for qp in queue.as_tuple()) == (pkt, )
def test_queue_with_service_passes_single_stored_packet_after_get_next_call(): t0, t1, t2, t3, t4 = 0, 13, 19, 22, 29 size = [100, 200, 300] sim, service = Mock(), Mock() sim.stime = t0 service_rev_conn = Mock() service.connections.set = Mock(return_value=service_rev_conn) queue = Queue(sim=sim) queue.connections.set('service', service, rname='queue') packets = [NetworkPacket(data=AppData(size=sz)) for sz in size] sim.stime = t1 queue.push(packets[0]) sim.stime = t2 queue.push(packets[1]) # Check that queue is updated, since no `get_next()` call was performed: assert tuple(qp.packet for qp in queue.as_tuple()) == tuple(packets[0:2]) sim.schedule.assert_not_called() # Check that after `get_next()` request the message is passed: sim.stime = t3 queue.get_next(service=service) assert tuple(qp.packet for qp in queue.as_tuple()) == (packets[1], ) sim.schedule.assert_called_once_with(0, service.handle_message, args=(packets[0], ), kwargs={ 'connection': service_rev_conn, 'sender': queue, }) sim.stime = t4 queue.push(packets[2]) assert tuple(qp.packet for qp in queue.as_tuple()) == tuple(packets[1:3]) # Also make sure that size updates were written: assert queue.size_trace.as_tuple() == ( (t0, 0), (t1, 1), (t2, 2), (t3, 1), (t4, 2), ) assert queue.bitsize_trace.as_tuple() == ( (t0, 0), (t1, size[0]), (t2, size[0] + size[1]), (t3, size[1]), (t4, size[1] + size[2]), ) assert queue.num_dropped == 0
def test_network_switch_increments_ssn_for_successive_packets_from_same_src(): """Validate when two packets come from 'user' to same dest, SSN increments. """ sim, ns, eth = Mock(), Mock(), Mock() switch = NetworkSwitch(sim) eth.address = 1 eth_conn = Mock() eth.connections.set = Mock(return_value=eth_conn) user_conn = switch.connections.set('user', ns, reverse=False) switch.connections.set('eth', eth, rname='network') switch.table.add(5, connection='eth', next_hop=2) switch.table.add(10, connection='eth', next_hop=3) pkt_1 = NetworkPacket(destination_address=5) pkt_2 = NetworkPacket(destination_address=10) switch.handle_message(pkt_1, connection=user_conn, sender=ns) switch.handle_message(pkt_2, connection=user_conn, sender=ns) assert pkt_2.osn > pkt_1.osn
def test_network_packet_creation(): data = Mock() packet = NetworkPacket(destination_address=10, originator_address=2, sender_address=5, receiver_address=6, osn=32, data=data) assert packet.destination_address == 10 assert packet.originator_address == 2 assert packet.sender_address == 5 assert packet.receiver_address == 6 assert packet.osn == 32 assert packet.data == data
def test_wired_transceiver_ignores_frames_not_from_peer(): sim, sender, switch = Mock(), Mock(), Mock() sim.stime = 0 iface = WiredTransceiver(sim) sim.schedule.reset_mock() # clear sim.schedule(0, iface.start) call pkt = NetworkPacket(data=AppData(size=100)) frame = WireFrame(pkt, duration=0.5, header_size=20, preamble=0.01) iface.connections.set('up', switch, reverse=False) sender_conn = iface.connections.set('wrong_name', sender, reverse=False) iface.handle_message(frame, sender=sender, connection=sender_conn) sim.schedule.assert_not_called() assert iface.rx_ready
def test_push_to_empty_queue_without_service_correctly_updates_content(): sim = Mock() sim.stime = 0 queue = Queue(sim, capacity=2) data_size = 123 packet = NetworkPacket(data=AppData(0, data_size, 0, 0)) queue.push(packet) assert not queue.empty() assert not queue.full() assert len(queue) == 1 assert queue.size() == 1 assert queue.bitsize() == data_size assert tuple(qp.packet for qp in queue.as_tuple()) == (packet, )
def test_wired_transceiver_drops_received_message_if_not_connected_to_switch(): sim, sender = Mock(), Mock() sim.stime = 0 iface = WiredTransceiver(sim) sender_conn = iface.connections.set('peer', sender, rname='peer') pkt = NetworkPacket(data=AppData(size=100)) frame = WireFrame(pkt, duration=0.5, header_size=20, preamble=0.01) iface.handle_message(frame, sender=sender, connection=sender_conn) sim.stime += frame.duration sim.schedule.reset_mock() iface.handle_rx_end(frame) sim.schedule.assert_not_called()
def test_push_up_to_full_queue_without_service_correctly_updates_content(): sim = Mock() sim.stime = 0 data_size = [123, 412] packets = [NetworkPacket(data=AppData(0, sz, 0, 0)) for sz in data_size] queue = Queue(sim, capacity=2) queue.push(packets[0]) queue.push(packets[1]) assert not queue.empty() assert queue.full() assert len(queue) == 2 assert queue.size() == 2 assert queue.bitsize() == sum(data_size) assert tuple(qp.packet for qp in queue.as_tuple()) == tuple(packets)
def test_wired_interface_forwards_packets_after_rx_end_to_user(): sim, queue, transceiver, user = Mock(), Mock(), Mock(), Mock() iface = WiredInterface(sim, 13, queue, transceiver) user_conn = iface.connections.set('user', user, rname='iface') int_receiver_conn = iface.connections['_receiver'] pkt = NetworkPacket(data=AppData(size=100)) iface.handle_message(pkt, connection=int_receiver_conn, sender=transceiver) sim.schedule.assert_called_once_with(0, user.handle_message, args=(pkt, ), kwargs={ 'connection': user_conn.reverse, 'sender': iface, })
def test_wired_interface_forwards_frames_from_wire_to_transceiver(): sim, queue, transceiver, peer = Mock(), Mock(), Mock(), Mock() iface = WiredInterface(sim, 13, queue, transceiver) peer_conn = iface.connections.set('wire', peer, rname='wire') frame = WireFrame(NetworkPacket(data=AppData(size=100))) iface.handle_message(frame, connection=peer_conn, sender=peer) int_peer_conn = iface.connections['_peer'] sim.schedule.assert_called_once_with(0, transceiver.handle_message, args=(frame, ), kwargs={ 'connection': int_peer_conn.reverse, 'sender': iface })
def test_network_switch_ignores_packets_to_unknown_destinations(): """Validate `NetworkSwitch` ignores messages without source not from 'user'. """ sim, ns, eth = Mock(), Mock(), Mock() switch = NetworkSwitch(sim) eth.address = 1 eth_conn = Mock() eth.connections.set = Mock(return_value=eth_conn) user_conn = switch.connections.set('invalid', ns, reverse=False) switch.connections.set('eth', eth, rname='network') switch.table.add(10, connection='eth', next_hop=2) pkt = NetworkPacket(destination_address=13) switch.handle_message(pkt, connection=user_conn, sender=ns) sim.schedule.assert_not_called()
def test_infinite_queue_stores_many_enough_packets(): n = 50 packets = [ NetworkPacket(data=AppData(0, uniform(0, 1000), 0, 0)) for _ in range(n) ] times = list(cumsum(uniform(0, 20, n))) sim = Mock() sim.stime = 0 queue = Queue(sim) for pkt, t in zip(packets, times): sim.stime = t queue.push(pkt) assert queue.size() == n assert len(queue.size_trace) == n + 1 assert queue.num_dropped == 0
def test_wired_transceiver_records_tx_statistics(bitrate, data_sizes, header_size, preamble, intervals, ifs): sim, receiver, queue = Mock(), Mock(), Mock() sim.stime = 0 iface = WiredTransceiver(sim, bitrate, header_size, preamble, ifs) iface.connections.set('peer', receiver, rname='peer') queue_conn = iface.connections.set('queue', queue, reverse=False) packets = [NetworkPacket(data=AppData(size=sz)) for sz in data_sizes] frame_sizes = [sz + header_size for sz in data_sizes] durations = [(sz + header_size) / bitrate + preamble for sz in data_sizes] t, timestamps = 0, [] for interval, duration in zip(intervals, durations): t_arrival = t + interval t_departure = t_arrival + duration + ifs timestamps.append((t_arrival, t_departure)) t = t_departure # Simulating transmit sequence for (t_arrival, t_departure), packet in zip(timestamps, packets): sim.stime = t_arrival iface.handle_message(packet, sender=queue, connection=queue_conn) sim.stime = t_departure - ifs iface.handle_tx_end() sim.stime = t_departure iface.handle_ifs_end() # Check TX statistics: expected_busy_trace = [(0, 0)] for t_arrival, t_departure in timestamps: expected_busy_trace.append((t_arrival, 1)) expected_busy_trace.append((t_departure, 0)) assert iface.num_transmitted_packets == len(packets) assert iface.num_transmitted_bits == sum(sz for sz in frame_sizes) assert iface.tx_busy_trace.as_tuple() == tuple(expected_busy_trace)
def test_network_switch_updates_addresses_when_forwarding_packet(): """Validate sender and receiver addresses are upon forwarding. """ sim, ns, wifi, eth = Mock(), Mock(), Mock(), Mock() switch = NetworkSwitch(sim) eth.address = 7 wifi.address = 199 wifi_rev_conn = Mock() wifi.connections.set = Mock(return_value=wifi_rev_conn) switch.connections.set('user', ns, reverse=False) switch.connections.set('wifi', wifi, rname='network') eth_conn = switch.connections.set('eth', eth, reverse=False) switch.table.add(230, 'wifi', 205) pkt = NetworkPacket(destination_address=230, originator_address=5, sender_address=6, receiver_address=7, osn=8) switch.handle_message(pkt, connection=eth_conn, sender=eth) sim.schedule.assert_called_once_with(0, wifi.handle_message, args=(pkt, ), kwargs={ 'connection': wifi_rev_conn, 'sender': switch, }) # These fields are expected to be updated assert pkt.sender_address == 199 assert pkt.receiver_address == 205 # These fields should be kept: assert pkt.osn == 8 assert pkt.originator_address == 5 assert pkt.destination_address == 230
def test_wired_transceiver_records_rx_statistics(bitrate, data_sizes, header_size, preamble, intervals): sim, sender = Mock(), Mock() sim.stime = 0 iface = WiredTransceiver(sim, bitrate, header_size, preamble) sender_conn = iface.connections.set('peer', sender, rname='peer') packets = [NetworkPacket(data=AppData(size=sz)) for sz in data_sizes] durations = [(sz + header_size) / bitrate + preamble for sz in data_sizes] frames = [ WireFrame(pkt, dt, header_size, preamble) for pkt, dt in zip(packets, durations) ] t, timestamps = 0, [] for interval, duration in zip(intervals, durations): t_arrival = t + interval t_departure = t_arrival + duration t = t_departure timestamps.append((t_arrival, t_departure)) # Simulating receive sequence for (t_arrival, t_departure), frame in zip(timestamps, frames): sim.stime = t_arrival iface.handle_message(frame, sender=sender, connection=sender_conn) sim.stime = t_departure iface.handle_rx_end(frame) # Check RX statistics: expected_busy_trace = [(0, 0)] for t_arrival, t_departure in timestamps: expected_busy_trace.append((t_arrival, 1)) expected_busy_trace.append((t_departure, 0)) assert iface.num_received_frames == len(frames) assert iface.num_received_bits == sum(frame.size for frame in frames) assert iface.rx_busy_trace.as_tuple() == tuple(expected_busy_trace)