# Path: topology/sniffer/sniffing_service.py
# class PacketExporter(Component):
#     """
#     Component used to export packets.
# 
#     The packets that are taken from the list of shared packets are then
#     discarded from the list of shared packets.
#     """
#     def __init__(self, shared_packets, lock):
#         self.shared_packets = shared_packets
#         self.lock = lock
# 
#     def process(self, unused=None):
#         """
#         :return: returns a list of packets as a dictionary
#         """
#         self.lock.acquire()
# 
#         packets = self.shared_packets[:]
#         self.shared_packets[:] = []
# 
#         self.lock.release()
#         return packets
# 
# Path: topology/sniffer/daemon.py
# class SniffingDaemon():
#     """
#     A daemon that itertes through a series of device connections
#     and gets sniffed devices.
#     """
#     def __init__(self, shared_packets, lock, connections=discover_devices):
#         """
#         :param shared_packets: a list of packets discovered by the sniffer
#         :param lock: the lock that protects the shared_packets list
#         :connections: the connections used to pool packets
#         """
#         self.packets = shared_packets
#         self.lock = lock
# 
#         # If the default argument was given, then we call discover_devices
#         if connections == discover_devices:
#             self.connections = discover_devices()
#         else:
#             self.connections = connections
# 
#     def get_new_packets(self, filter_mask="10.1.1.1/32"):
#         """
#         Updates the list of shared packets via new packests provided through
#         scans.
# 
#         For the moment we ask each device for a packet. If this proves to
#         be a problem, we need to group the reads.
# 
#         :param filter_mask: the filter mask of form `IP/bits` used to filter
#             the GOOD packets
#         :return: returns nothing
#         """
#         new_packets = []
#         for connection in self.connections:
#             try:
#                 (header, packet) = connection.next()
#                 packet = parse_packet(packet)
#                 packet = filter_packet(packet, filter_mask)
#                 if packet is not None:
#                     new_packets.append(packet)
#                     logger.debug(packet)
#             except Exception as e:
#                 # Non-eth packets received
#                 pass
# 
#         self.lock.acquire()
# 
#         for packet in new_packets:
#             self.packets.append(packet)
# 
#         self.lock.release()
# 
#     def run(self, filter_mask="10.1.1.1/32"):
#         while True:
#             self.get_new_packets(filter_mask)


from unittest import TestCase
from topology.sniffer.sniffing_service import PacketExporter
from topology.sniffer.daemon import SniffingDaemon
from unittest.mock import MagicMock
class TestSniffingDaemon(TestCase):
    RAW_TCP_PACKET = b'\\\x93\xa2\xf4\xf7\xf6\xf0\x9f\xc2\x18\xa2\xdf\x08\x00E\x00\x004x\x98@\x00:\x06\x84Yh\x10\x19\xeb\xc0\xa8\x01/\x01\xbb\xb0\xf0v\xb1j.\xc2^L\xe3\x80\x10\x00 t\x99\x00\x00\x01\x01\x05\n\xc2^L\xc3\xc2^L\xe3'
    RES_TCP_PACKET = {'dest': '192.168.1.47', 'src': '104.16.25.235', 'version': '4', 'ip_header_length': '5', 'ttl': '58', 'transport': { 'src_port': '443', 'ack': '3260959971', 'dest_port': '45296', 'seq': '1991338542'}, 'transport_type': 'TCP'}

    def good_connection(self):
        connection = lambda: None
        connection.next = MagicMock(return_value = ("", self.RAW_TCP_PACKET))
        return connection

    def bad_connection(self):
        connection = lambda: None
        connection.next = MagicMock(return_value = ("", b'sarmale'))
        return connection

    def test_single_connection_gets_good_packet(self):
        packets, lock = [], GiveUpLock()
        sniffer = SniffingDaemon(packets, lock, [self.good_connection()])
        sniffer.get_new_packets()

        self.assertListEqual(packets, [self.RES_TCP_PACKET])

    def test_malformated_packets_are_dropped(self):
        packets, lock = [], GiveUpLock()
        sniffer = SniffingDaemon(packets, lock, [self.bad_connection()])
        sniffer.get_new_packets()

        self.assertListEqual(packets, [])

    def test_packets_from_all_connections_are_fetched(self):
        packets, lock = [], GiveUpLock()

# Path: topology/sniffer/sniffing_service.py
# class PacketExporter(Component):
#     """
#     Component used to export packets.
# 
#     The packets that are taken from the list of shared packets are then
#     discarded from the list of shared packets.
#     """
#     def __init__(self, shared_packets, lock):
#         self.shared_packets = shared_packets
#         self.lock = lock
# 
#     def process(self, unused=None):
#         """
#         :return: returns a list of packets as a dictionary
#         """
#         self.lock.acquire()
# 
#         packets = self.shared_packets[:]
#         self.shared_packets[:] = []
# 
#         self.lock.release()
#         return packets
# 
# Path: topology/sniffer/daemon.py
# class SniffingDaemon():
#     """
#     A daemon that itertes through a series of device connections
#     and gets sniffed devices.
#     """
#     def __init__(self, shared_packets, lock, connections=discover_devices):
#         """
#         :param shared_packets: a list of packets discovered by the sniffer
#         :param lock: the lock that protects the shared_packets list
#         :connections: the connections used to pool packets
#         """
#         self.packets = shared_packets
#         self.lock = lock
# 
#         # If the default argument was given, then we call discover_devices
#         if connections == discover_devices:
#             self.connections = discover_devices()
#         else:
#             self.connections = connections
# 
#     def get_new_packets(self, filter_mask="10.1.1.1/32"):
#         """
#         Updates the list of shared packets via new packests provided through
#         scans.
# 
#         For the moment we ask each device for a packet. If this proves to
#         be a problem, we need to group the reads.
# 
#         :param filter_mask: the filter mask of form `IP/bits` used to filter
#             the GOOD packets
#         :return: returns nothing
#         """
#         new_packets = []
#         for connection in self.connections:
#             try:
#                 (header, packet) = connection.next()
#                 packet = parse_packet(packet)
#                 packet = filter_packet(packet, filter_mask)
#                 if packet is not None:
#                     new_packets.append(packet)
#                     logger.debug(packet)
#             except Exception as e:
#                 # Non-eth packets received
#                 pass
# 
#         self.lock.acquire()
# 
#         for packet in new_packets:
#             self.packets.append(packet)
# 
#         self.lock.release()
# 
#     def run(self, filter_mask="10.1.1.1/32"):
#         while True:
#             self.get_new_packets(filter_mask)


# Path: tests/topology/sniffer/test_daemon.py
from unittest import TestCase
from topology.sniffer.sniffing_service import PacketExporter
from topology.sniffer.daemon import SniffingDaemon
from unittest.mock import MagicMock

class TestSniffingDaemon(TestCase):
    RAW_TCP_PACKET = b'\\\x93\xa2\xf4\xf7\xf6\xf0\x9f\xc2\x18\xa2\xdf\x08\x00E\x00\x004x\x98@\x00:\x06\x84Yh\x10\x19\xeb\xc0\xa8\x01/\x01\xbb\xb0\xf0v\xb1j.\xc2^L\xe3\x80\x10\x00 t\x99\x00\x00\x01\x01\x05\n\xc2^L\xc3\xc2^L\xe3'
    RES_TCP_PACKET = {'dest': '192.168.1.47', 'src': '104.16.25.235', 'version': '4', 'ip_header_length': '5', 'ttl': '58', 'transport': { 'src_port': '443', 'ack': '3260959971', 'dest_port': '45296', 'seq': '1991338542'}, 'transport_type': 'TCP'}

    def good_connection(self):
        connection = lambda: None
        connection.next = MagicMock(return_value = ("", self.RAW_TCP_PACKET))
        return connection

    def bad_connection(self):
        connection = lambda: None
        connection.next = MagicMock(return_value = ("", b'sarmale'))
        return connection

    def test_single_connection_gets_good_packet(self):
        packets, lock = [], GiveUpLock()
        sniffer = SniffingDaemon(packets, lock, [self.good_connection()])
        sniffer.get_new_packets()

        self.assertListEqual(packets, [self.RES_TCP_PACKET])

    def test_malformated_packets_are_dropped(self):
        packets, lock = [], GiveUpLock()
        sniffer = SniffingDaemon(packets, lock, [self.bad_connection()])
        sniffer.get_new_packets()

        self.assertListEqual(packets, [])

    def test_packets_from_all_connections_are_fetched(self):
        packets, lock = [], GiveUpLock()

        sniffer = SniffingDaemon(packets, lock, [self.good_connection()] * 10 + [self.bad_connection] * 5)