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_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_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_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_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_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_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_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_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_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_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_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_app_data_is_immutable(): app_data = AppData(dest_addr=5, size=20, source_id=13, created_at=123) assert app_data.destination_address == 5 assert app_data.size == 20 assert app_data.source_id == 13 assert app_data.created_at == 123 with pytest.raises(AttributeError): app_data.destination_address = 11 with pytest.raises(AttributeError): app_data.size = 21 with pytest.raises(AttributeError): app_data.source_id = 26 with pytest.raises(AttributeError): app_data.created_at = 234
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_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)
def test_push_to_full_queue_without_service_drops_last_packet(): 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=1) queue.push(packets[0]) # Check that num_dropped counter is 0 before overflow: assert queue.num_dropped == 0 # Pushing a packet that will overflow the queue: queue.push(packets[1]) assert queue.num_dropped == 1 # Now check that only first packet is in the queue: assert not queue.empty() assert queue.full() assert len(queue) == 1 assert queue.size() == 1 assert queue.bitsize() == data_size[0] assert tuple(qp.packet for qp in queue.as_tuple()) == (packets[0], )
def test_wired_interface_integration_receives_frame(): sim, user, peer = Mock(), Mock(), Mock() sim.stime = 10 from pycsmaca.simulations.modules.queues import Queue queue = Queue(sim) transceiver = WiredTransceiver(sim, 1000, 22, 0.1, 0.05) iface = WiredInterface(sim, 0, queue=queue, transceiver=transceiver) user_rev_conn = Mock() user.connections.set = Mock(return_value=user_rev_conn) iface.connections.set('user', user, rname='iface') wire_rev_conn = Mock() peer.connections.set = Mock(return_value=wire_rev_conn) wire_conn = iface.connections.set('wire', peer, rname='wire') packet = NetworkPacket(data=AppData(size=242)) duration = (packet.size + transceiver.header_size ) / transceiver.bitrate + transceiver.preamble frame = WireFrame(packet, duration, transceiver.header_size, transceiver.preamble) transceiver_peer_conn = iface.connections['_peer'].reverse _receiver_conn = iface.connections['_receiver'] # 1) Simulate like a frame came from the peer: iface.handle_message(frame, connection=wire_conn, sender=peer) sim.schedule.assert_called_with(0, transceiver.handle_message, args=(frame, ), kwargs={ 'connection': transceiver_peer_conn, 'sender': iface, }) sim.schedule.reset_mock() # 2) Execute transceiver frame reception start, update time and # execute transceiver frame reception end. Then make sure that # packet was scheduled for sending up to the interface via 'up': transceiver.handle_message(frame, transceiver_peer_conn, iface) sim.schedule.assert_called_with(duration, transceiver.handle_rx_end, args=(frame, )) sim.schedule.reset_mock() sim.stime += duration transceiver.handle_rx_end(frame) sim.schedule.assert_called_with(0, iface.handle_message, args=(packet, ), kwargs={ 'connection': _receiver_conn, 'sender': transceiver, }) sim.schedule.reset_mock() # 3) Execute interface packet reception, make sure it is delivered to user: iface.handle_message(packet, _receiver_conn, transceiver) sim.schedule.assert_called_with(0, user.handle_message, args=(packet, ), kwargs={ 'connection': user_rev_conn, 'sender': iface, }) sim.schedule.reset_mock()
def test_wired_interface_integration_serves_user_packet(): sim, user, peer = Mock(), Mock(), Mock() sim.stime = 10 from pycsmaca.simulations.modules.queues import Queue queue = Queue(sim) transceiver = WiredTransceiver(sim, 1000, 22, 0.03, 0.05) iface = WiredInterface(sim, 1, queue=queue, transceiver=transceiver) user_conn = iface.connections.set('user', user, rname='iface') wire_rev_conn = Mock() peer.connections.set = Mock(return_value=wire_rev_conn) wire_conn = iface.connections.set('wire', peer, rname='wire') wire_conn.delay = 0.01 user_pkt = NetworkPacket(data=AppData(size=100)) transceiver_queue_conn = transceiver.connections['queue'] queue_iface_conn = iface.connections['_queue'].reverse iface_transceiver_conn = iface.connections['_peer'] # First of all, we need to force transceiver start, since no actual # simulation execution is performed: transceiver.start() # 1) Simulate like a new packet arrived from user, make sure that queue # delivery was scheduled: iface.handle_message(user_pkt, connection=user_conn, sender=user) sim.schedule.assert_called_with(0, queue.handle_message, args=(user_pkt, ), kwargs={ 'connection': queue_iface_conn, 'sender': iface, }) sim.schedule.reset_mock() # 2) Force execution of queue packet delivery, make sure the packet arrives # at the transceiver: queue.handle_message(user_pkt, queue_iface_conn, iface) sim.schedule.assert_called_with(0, transceiver.handle_message, args=(user_pkt, ), kwargs={ 'connection': transceiver_queue_conn, 'sender': queue, }) sim.schedule.reset_mock() # 3) Force packet handling at the transceiver and make sure it schedules # packet delivery at its peer (iface itself): transceiver.handle_message(user_pkt, connection=transceiver_queue_conn, sender=queue) frame = transceiver.tx_frame sim.schedule.assert_any_call(0, iface.handle_message, args=(frame, ), kwargs={ 'connection': iface_transceiver_conn, 'sender': transceiver, }) assert frame.packet == user_pkt sim.schedule.reset_mock() # 4) Finally, force frame arrival at the interface and make sure it # schedules frame reception at its peer after the channel delay: iface.handle_message(frame, iface_transceiver_conn, transceiver) sim.schedule.assert_called_with(wire_conn.delay, peer.handle_message, args=(frame, ), kwargs={ 'connection': wire_rev_conn, 'sender': iface, })
def test_app_data_provides_str(): app_data = AppData(dest_addr=1, size=250, source_id=2, created_at=10) assert str(app_data) == 'AppData{sid=2,dst=1,size=250,ct=10}'
def test_queue_with_several_services_finds_right_connections(): sim, blue, red, green = Mock(), Mock(), Mock(), Mock() sim.stime = 0 blue_rev_conn = Mock() blue.connections.set = Mock(return_value=blue_rev_conn) red_rev_conn = Mock() red.connections.set = Mock(return_value=red_rev_conn) green_rev_conn = Mock() green.connections.set = Mock(return_value=green_rev_conn) queue = Queue(sim=sim) queue.connections.set('blue', blue, rname='queue') queue.connections.set('red', red, rname='queue') queue.connections.set('green', green, rname='queue') # First, we fill the queue: pkt_1 = NetworkPacket(data=AppData(size=100)) pkt_2 = NetworkPacket(data=AppData(size=200)) pkt_3 = NetworkPacket(data=AppData(size=300)) # Now, while queue is empty, two services request data: sim.stime = 0.5 queue.get_next(green) sim.stime = 1.0 queue.get_next(blue) # At some moment, a packet arrives. It should be passed to the module that # first requested the packet: sim.stime = 2 queue.push(pkt_1) sim.schedule.assert_called_once_with(0, green.handle_message, args=(pkt_1, ), kwargs={ 'connection': green_rev_conn, 'sender': queue, }) assert queue.as_tuple() == () sim.schedule.reset_mock() # At the next moment, another packet arrives and is being passed to the # module that requested data after the first one: sim.stime = 5 queue.push(pkt_2) sim.schedule.assert_called_once_with(0, blue.handle_message, args=(pkt_2, ), kwargs={ 'connection': blue_rev_conn, 'sender': queue, }) assert queue.as_tuple() == () sim.schedule.reset_mock() # Now another packet arrives, and it should be stored since both requests # were fulfilled previously: sim.stime = 10 queue.push(pkt_3) assert tuple(qp.packet for qp in queue.as_tuple()) == (pkt_3, ) sim.schedule.assert_not_called() # Finally, the another module requests a packet, and it is immediately # delivered to it: sim.stime = 19 queue.get_next(red) sim.schedule.assert_called_once_with(0, red.handle_message, args=(pkt_3, ), kwargs={ 'connection': red_rev_conn, 'sender': queue, })
def test_app_data_supports_default_values(): app_data = AppData() assert app_data.destination_address == 0 assert app_data.size == 0 assert app_data.source_id == 0 assert app_data.created_at == 0
def test_wired_transceiver_is_full_duplex(bitrate, header_size, preamble, size): sim, peer, queue, switch = Mock(), Mock(), Mock(), Mock() sim.stime = 0 eth = WiredTransceiver(sim, header_size=header_size, bitrate=bitrate, preamble=preamble, ifs=0) peer_conn = eth.connections.set('peer', peer, reverse=False) queue_conn = eth.connections.set('queue', queue, reverse=False) eth.connections.set('up', switch, reverse=False) inp_pkt = NetworkPacket(data=AppData(size=size)) out_pkt_1 = NetworkPacket(data=AppData(size=size)) out_pkt_2 = NetworkPacket(data=AppData(size=size)) duration = (header_size + size) / bitrate + preamble frame = WireFrame(inp_pkt, duration=duration, header_size=header_size, preamble=preamble) # 1) Transceiver starts transmitting `out_pkt_1`: sim.stime = 0 eth.start() eth.handle_message(out_pkt_1, queue_conn, queue) assert eth.tx_busy assert eth.rx_ready sim.schedule.assert_any_call(duration, eth.handle_tx_end) sim.schedule.assert_any_call(0, peer.handle_message, args=ANY, kwargs=ANY) sim.schedule.reset_mock() # 2) Then, after 2/3 of the packet was transmitted, a packet arrives: sim.stime = 2 * duration / 3 eth.handle_message(frame, peer_conn, peer) assert eth.tx_busy assert eth.rx_busy sim.schedule.assert_called_with(duration, eth.handle_rx_end, args=(frame, )) sim.schedule.reset_mock() # 3) After duration, call handle_tx_end and handle_ifs_end: sim.stime = duration eth.handle_tx_end() eth.handle_ifs_end() assert eth.tx_ready assert eth.rx_busy sim.schedule.reset_mock() # 4) After another 1/3 duration start new TX (during RX this time): sim.stime = 4 / 3 * duration eth.handle_message(out_pkt_2, queue_conn, queue) assert eth.tx_busy assert eth.rx_busy sim.schedule.assert_any_call(duration, eth.handle_tx_end) sim.schedule.assert_any_call(0, peer.handle_message, args=ANY, kwargs=ANY) sim.schedule.reset_mock() # 5) After 5/3 duration, RX ends, but TX still goes on: sim.stime = 5 / 3 * duration eth.handle_rx_end(frame) assert eth.tx_busy assert eth.rx_ready sim.schedule.assert_called_with(0, switch.handle_message, args=ANY, kwargs=ANY)
def test_wired_transceiver_packet_from_queue_transmission( bitrate, header_size, preamble, ifs): sim = Mock() iface = WiredTransceiver( sim, bitrate=bitrate, header_size=header_size, preamble=preamble, ifs=ifs, ) # Now we connect the transceiver with a queue and start it. Make sure # that the queue is connected via 'queue' link, and after start `get_next()` # is called. queue = Mock() queue_rev_conn = Mock() queue.connections.set = Mock(return_value=queue_rev_conn) queue_conn = iface.connections.set('queue', queue, rname='iface') queue.get_next.assert_not_called() iface.start() # start of the transceiver causes `get_next()` call queue.get_next.assert_called_once_with(iface) queue.get_next.reset_mock() assert iface.started and iface.tx_ready and not iface.tx_busy # # After being started, transceiver expects a `NetworkPacket` in its # handle_message() call. We connect another mock to the transceiver via # 'peer' connection and make sure that after the call that `send()` was # called on that peer connection. # # Since `WireFrame` objects are expected to be used in connections # between peers, we patch them. # peer = Mock() peer_rev_conn = Mock() peer.connections.set = Mock(return_value=peer_rev_conn) iface.connections.set('peer', peer, rname='peer') packet = NetworkPacket(data=AppData(size=500)) duration = (packet.size + header_size) / bitrate + preamble with patch(WIRE_FRAME_CLASS) as WireFrameMock: frame_kwargs = { 'packet': packet, 'header_size': header_size, 'duration': duration, 'preamble': preamble, } frame_instance = Mock() frame_instance.duration = duration frame_instance.size = header_size + packet.size WireFrameMock.return_value = frame_instance sim.stime = 0 iface.handle_message(packet, sender=queue, connection=queue_conn) sim.schedule.assert_any_call(0, peer.handle_message, args=(frame_instance, ), kwargs={ 'connection': peer_rev_conn, 'sender': iface, }) WireFrameMock.assert_called_once_with(**frame_kwargs) # Also check that wired transceiver scheduled a timeout: sim.schedule.assert_any_call(duration, iface.handle_tx_end) # .. and that now transceiver is busy: assert iface.started and not iface.tx_ready and iface.tx_busy sim.schedule.reset_mock() # Now we imitate `handle_tx_end()` call, make sure that after that the # transceiver is not yet ready, but schedules `handle_ifs_end()`: sim.stime = duration iface.handle_tx_end() sim.schedule.assert_called_once_with(ifs, iface.handle_ifs_end) assert iface.started and not iface.tx_ready and iface.tx_busy # After the IFS waiting finished, transceiver is expected to call # `queue.get_next(iface)` and be ready for new packets: sim.stime += ifs iface.handle_ifs_end() queue.get_next.assert_called_once_with(iface) assert iface.started and iface.tx_ready and not iface.tx_busy