예제 #1
0
    def test_extract_frame_multi(self):
        """ Test the handling of multiple concatenated messages by the buffer. """

        m1 = b'CONNECT\nsession:207567f3-cce7-4a0a-930b-46fc394dd53d\n\n0123456789\x00'
        m2 = b'SUBSCRIBE\nack:auto\ndestination:/queue/test\n\n\x00SEND\ndestination:/queue/test\n\n\x00'

        sb = FrameBuffer()
        sb.append(m1)
        f1 = sb.extract_frame()
        self.assertEqual(f1.cmd, frames.CONNECT)
        self.assertEqual(f1.body, b'0123456789')

        f = sb.extract_frame()

        self.assertIsNone(f)

        sb.append(m2)
        f2 = sb.extract_frame()
        f3 = sb.extract_frame()

        self.assertEqual(f2.cmd, frames.SUBSCRIBE)
        self.assertEqual(f2.body, '')
        self.assertEqual(f3.cmd, frames.SEND)
        self.assertEqual(f3.headers.get('destination'), '/queue/test')
        self.assertEqual(f3.body, '')

        self.assertIsNone(sb.extract_frame())
예제 #2
0
 def test_extract_frame(self):
     """ Test extracting a single frame. """
     sb = FrameBuffer()
     m1 = self.createMessage(
         'connect', {'session': uuid.uuid4()}, 'This is the body')
     sb.append(m1)
     msg = sb.extract_frame()
     self.assertIsInstance(msg, Frame)
     self.assertEqual(m1, msg.pack())
예제 #3
0
 def test_extract_frame_binary(self):
     """ Test extracting a binary frame. """
     sb = FrameBuffer()
     binmsg = "\x00\x00HELLO\x00\x00DONKEY\x00\x00"
     m1 = self.createMessage('send', OrderedDict({'content-length': len(binmsg), 'x-other-header': 'value'}), binmsg
                             )
     sb.append(m1)
     msg = sb.extract_frame()
     self.assertIsInstance(msg, Frame)
     self.assertEqual(msg.pack(), m1)
예제 #4
0
 def setup(self):
     if self.server.timeout is not None:
         self.request.settimeout(self.server.timeout)
     self.debug = False
     self.log = logging.getLogger(
         '%s.%s' % (self.__module__, self.__class__.__name__))
     self.buffer = FrameBuffer()
     self.engine = StompEngine(connection=self,
                               authenticator=self.server.authenticator,
                               queue_manager=self.server.queue_manager,
                               topic_manager=self.server.topic_manager,
                               protocol=self.server.protocol)
 def __init__(self, addr, connect=True):
     """
     @param addr: The (host,port) tuple for connection.
     @type addr: C{tuple}
     @param connect: Whether to connect socket to specified addr.
     @type connect: C{bool}
     """
     self.log = logging.getLogger(
         '%s.%s' % (self.__module__, self.__class__.__name__))
     self.sock = None
     self.addr = addr
     self.received_frames = Queue()
     self.read_stopped = threading.Event()
     self.buffer = FrameBuffer()
     if connect:
         self._connect()
예제 #6
0
    def test_iteration(self):
        """ Test the iteration feature of our buffer."""
        sb = FrameBuffer()
        m1 = self.createMessage(
            frames.CONNECT, {'session': uuid.uuid4()}, b'This is the body')
        m2 = self.createMessage(
            frames.SEND, {'destination': '/queue/sample'}, b'This is the body-2')
        sb.append(m1)
        sb.append(m2)

        self.assertIs(sb, iter(sb))

        idx = 0
        expected = (m1, m2)
        for frame in sb:
            self.assertIsInstance(frame, Frame)
            self.assertEqual(expected[idx], frame.pack())
            idx += 1

        self.assertEqual(idx, 2)
예제 #7
0
 def setup(self):
     if self.server.timeout is not None:
         self.request.settimeout(self.server.timeout)
     self.debug = False
     self.log = logging.getLogger('%s.%s' % (self.__module__, self.__class__.__name__))
     self.buffer = FrameBuffer()
     self.engine = StompEngine(connection=self,
                               authenticator=self.server.authenticator,
                               queue_manager=self.server.queue_manager,
                               topic_manager=self.server.topic_manager,
                               protocol=self.server.protocol)
예제 #8
0
    def __init__(self, addr, connect=True):
        """
        @param addr: The (host,port) tuple for connection.
        @type addr: C{tuple}

        @param connect: Whether to connect socket to specified addr.
        @type connect: C{bool}
        """
        self.log = logging.getLogger('%s.%s' % (
            self.__module__, self.__class__.__name__))
        self.sock = None
        self.addr = addr
        self.received_frames = Queue()
        self.read_stopped = threading.Event()
        self.buffer = FrameBuffer()
        if connect:
            self._connect()
class TestStompClient(object):
    """
    A stomp client for use in testing.
    This client spawns a listener thread and pushes anything that comes in onto the
    read_frames queue.
    @ivar received_frames: A queue of Frame instances that have been received.
    @type received_frames: C{Queue.Queue} containing any received C{stompclient.frame.Frame}
    """
    def __init__(self, addr, connect=True):
        """
        @param addr: The (host,port) tuple for connection.
        @type addr: C{tuple}
        @param connect: Whether to connect socket to specified addr.
        @type connect: C{bool}
        """
        self.log = logging.getLogger(
            '%s.%s' % (self.__module__, self.__class__.__name__))
        self.sock = None
        self.addr = addr
        self.received_frames = Queue()
        self.read_stopped = threading.Event()
        self.buffer = FrameBuffer()
        if connect:
            self._connect()

    def connect(self, headers=None):
        self.send_frame(Frame(frames.CONNECT, headers=headers))

    def send(self,
             destination,
             message,
             set_content_length=True,
             extra_headers=None):
        headers = extra_headers or {}
        headers['destination'] = destination
        if set_content_length:
            headers['content-length'] = len(message)
        self.send_frame(Frame('send', headers=headers, body=message))

    def subscribe(self, destination):
        self.send_frame(
            Frame('subscribe', headers={'destination': destination}))

    def send_frame(self, frame):
        """
        Sends a stomp frame.
        @param frame: The stomp frame to send.
        @type frame: L{stompclient.frame.Frame}
        """
        if not self.connected:
            raise RuntimeError("Not connected")
        self.sock.send(frame.pack())

    def _connect(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect(self.addr)
        self.connected = True
        self.read_stopped.clear()
        t = threading.Thread(target=self._read_loop,
                             name="client-receiver-%s" % hex(id(self)))
        t.start()

    def _read_loop(self):
        while self.connected:
            r, w, e = select.select([self.sock], [], [], 0.1)
            if r:
                data = self.sock.recv(1024)
                self.buffer.append(data)
                for frame in self.buffer:
                    self.log.debug("Processing frame: %s" % frame)
                    self.received_frames.put(frame)
        self.read_stopped.set()
        # print "Read loop has been quit! for %s" % id(self)

    def disconnect(self):
        self.send_frame(Frame('disconnect'))

    def close(self):
        if not self.connected:
            raise RuntimeError("Not connected")
        self.connected = False
        self.read_stopped.wait(timeout=0.5)
        self.sock.close()
예제 #10
0
class StompRequestHandler(BaseRequestHandler, StompConnection):
    """
    Class that will be instantiated to handle STOMP connections.

    This class will be instantiated once per connection to the server.  In a multi-threaded
    context, that means that instances of this class are scoped to a single thread.  It should
    be noted that while the L{coilmq.engine.StompEngine} instance will be thread-local, the 
    storage containers configured into the engine are not thread-local (and hence must be
    thread-safe). 

    @ivar buffer: A StompBuffer instance which buffers received data (to ensure we deal with
                    complete STOMP messages.
    @type buffer: C{stompclient.util.FrameBuffer}

    @ivar engine: The STOMP protocol engine.
    @type engine: L{coilmq.engine.StompEngine}

    @ivar debug: Whether to enable extra-verbose debug logging.  (Will be logged at debug level.)
    @type debug: C{bool}
    """
    def setup(self):
        if self.server.timeout is not None:
            self.request.settimeout(self.server.timeout)
        self.debug = False
        self.log = logging.getLogger(
            '%s.%s' % (self.__module__, self.__class__.__name__))
        self.buffer = FrameBuffer()
        self.engine = StompEngine(connection=self,
                                  authenticator=self.server.authenticator,
                                  queue_manager=self.server.queue_manager,
                                  topic_manager=self.server.topic_manager,
                                  protocol=self.server.protocol)

    def handle(self):
        """
        Handle a new socket connection.
        """
        # self.request is the TCP socket connected to the client
        try:
            while not self.server._shutdown_request_event.is_set():
                try:
                    data = self.request.recv(8192)
                    if not data:
                        break
                    if self.debug:
                        self.log.debug("RECV: %r" % data)
                    self.buffer.append(data)

                    for frame in self.buffer:
                        self.server.frames_queue.put(frame)
                        self.log.debug("Processing frame: %s" % frame)
                        self.engine.process_frame(frame)
                        if not self.engine.connected:
                            raise ClientDisconnected()
                except socket.timeout:  # pragma: no cover
                    pass
        except ClientDisconnected:
            self.log.debug("Client disconnected, discontinuing read loop.")
        except Exception as e:  # pragma: no cover
            self.log.error("Error receiving data (unbinding): %s" % e)
            self.engine.unbind()
            raise

    def finish(self):
        """
        Normal (non-error) termination of request.

        Unbinds the engine.
        @see: L{coilmq.engine.StompEngine.unbind}
        """
        self.engine.unbind()

    def send_frame(self, frame):
        """ Sends a frame to connected socket client.

        @param frame: The frame to send.
        @type frame: C{stompclient.frame.Frame}
        """
        packed = frame.pack()
        if self.debug:  # pragma: no cover
            self.log.debug("SEND: %r" % packed)
        self.request.sendall(packed)
예제 #11
0
class TestStompClient(object):
    """
    A stomp client for use in testing.

    This client spawns a listener thread and pushes anything that comes in onto the 
    read_frames queue.

    @ivar received_frames: A queue of Frame instances that have been received.
    @type received_frames: C{Queue.Queue} containing any received C{stompclient.frame.Frame}
    """

    def __init__(self, addr, connect=True):
        """
        @param addr: The (host,port) tuple for connection.
        @type addr: C{tuple}

        @param connect: Whether to connect socket to specified addr.
        @type connect: C{bool}
        """
        self.log = logging.getLogger('%s.%s' % (
            self.__module__, self.__class__.__name__))
        self.sock = None
        self.addr = addr
        self.received_frames = Queue()
        self.read_stopped = threading.Event()
        self.buffer = FrameBuffer()
        if connect:
            self._connect()

    def connect(self, headers=None):
        self.send_frame(Frame(frames.CONNECT, headers=headers))

    def send(self, destination, message, set_content_length=True, extra_headers=None):
        headers = extra_headers or {}
        headers['destination'] = destination
        if set_content_length:
            headers['content-length'] = len(message)
        self.send_frame(Frame('send', headers=headers, body=message))

    def subscribe(self, destination):
        self.send_frame(Frame('subscribe', headers={
                        'destination': destination}))

    def send_frame(self, frame):
        """
        Sends a stomp frame.
        @param frame: The stomp frame to send.
        @type frame: L{stompclient.frame.Frame}
        """
        if not self.connected:
            raise RuntimeError("Not connected")
        self.sock.send(frame.pack())

    def _connect(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect(self.addr)
        self.connected = True
        self.read_stopped.clear()
        t = threading.Thread(target=self._read_loop,
                             name="client-receiver-%s" % hex(id(self)))
        t.start()

    def _read_loop(self):
        while self.connected:
            r, w, e = select.select([self.sock], [], [], 0.1)
            if r:
                data = self.sock.recv(1024)
                self.buffer.append(data)
                for frame in self.buffer:
                    self.log.debug("Processing frame: %s" % frame)
                    self.received_frames.put(frame)
        self.read_stopped.set()
        # print "Read loop has been quit! for %s" % id(self)

    def disconnect(self):
        self.send_frame(Frame('disconnect'))

    def close(self):
        if not self.connected:
            raise RuntimeError("Not connected")
        self.connected = False
        self.read_stopped.wait(timeout=0.5)
        self.sock.close()
예제 #12
0
class StompRequestHandler(BaseRequestHandler, StompConnection):
    """
    Class that will be instantiated to handle STOMP connections.

    This class will be instantiated once per connection to the server.  In a multi-threaded
    context, that means that instances of this class are scoped to a single thread.  It should
    be noted that while the L{coilmq.engine.StompEngine} instance will be thread-local, the 
    storage containers configured into the engine are not thread-local (and hence must be
    thread-safe). 

    @ivar buffer: A StompBuffer instance which buffers received data (to ensure we deal with
                    complete STOMP messages.
    @type buffer: C{stompclient.util.FrameBuffer}

    @ivar engine: The STOMP protocol engine.
    @type engine: L{coilmq.engine.StompEngine}

    @ivar debug: Whether to enable extra-verbose debug logging.  (Will be logged at debug level.)
    @type debug: C{bool}
    """

    def setup(self):
        if self.server.timeout is not None:
            self.request.settimeout(self.server.timeout)
        self.debug = False
        self.log = logging.getLogger('%s.%s' % (self.__module__, self.__class__.__name__))
        self.buffer = FrameBuffer()
        self.engine = StompEngine(connection=self,
                                  authenticator=self.server.authenticator,
                                  queue_manager=self.server.queue_manager,
                                  topic_manager=self.server.topic_manager,
                                  protocol=self.server.protocol)

    def handle(self):
        """
        Handle a new socket connection.
        """
        # self.request is the TCP socket connected to the client
        try:
            while not self.server._shutdown_request_event.is_set():
                try:
                    data = self.request.recv(8192)
                    if not data:
                        break
                    if self.debug:
                        self.log.debug("RECV: %r" % data)
                    self.buffer.append(data)

                    for frame in self.buffer:
                        self.log.debug("Processing frame: %s" % frame)
                        self.engine.process_frame(frame)
                        if not self.engine.connected:
                            raise ClientDisconnected()
                except socket.timeout:  # pragma: no cover
                    pass
        except ClientDisconnected:
            self.log.debug("Client disconnected, discontinuing read loop.")
        except Exception as e:  # pragma: no cover
            self.log.error("Error receiving data (unbinding): %s" % e)
            self.engine.unbind()
            raise

    def finish(self):
        """
        Normal (non-error) termination of request.

        Unbinds the engine.
        @see: L{coilmq.engine.StompEngine.unbind}
        """
        self.engine.unbind()

    def send_frame(self, frame):
        """ Sends a frame to connected socket client.

        @param frame: The frame to send.
        @type frame: C{stompclient.frame.Frame}
        """
        packed = frame.pack()
        if self.debug:  # pragma: no cover
            self.log.debug("SEND: %r" % packed)
        self.request.sendall(packed)