def test_deliver_baddata(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test\r\n') self.sock.sendall(b'EHLO there\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall( b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n' ) self.sock.recv( IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n') self.sock.sendall( b'From: [email protected]\r\n\r\ntest test\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'450 Yikes\r\n') self.sock.sendall(b'RSET\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.mox.ReplayAll() client = SmtpRelayClient(('addr', 0), self.queue, socket_creator=self._socket_creator, ehlo_as='there') client._connect() client._ehlo() client._deliver(result, env) with self.assertRaises(TransientRelayError): result.get_nowait()
def test_run_multiple(self): result1 = AsyncResult() result2 = AsyncResult() env1 = Envelope('*****@*****.**', ['*****@*****.**']) env1.parse(b'From: [email protected]\r\n\r\ntest test\r\n') env2 = Envelope('*****@*****.**', ['*****@*****.**']) env2.parse(b'From: [email protected]\r\n\r\ntest test\r\n') queue = BlockingDeque() queue.append((result1, env1)) queue.append((result2, env2)) self.sock.recv(IsA(int)).AndReturn(b'220 Welcome\r\n') self.sock.sendall(b'EHLO test\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall(b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n') self.sock.sendall(b'From: [email protected]\r\n\r\ntest test\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall(b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n') self.sock.sendall(b'From: [email protected]\r\n\r\ntest test\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall(b'QUIT\r\n') self.sock.recv(IsA(int)).AndReturn(b'221 Goodbye\r\n') self.sock.close() self.mox.ReplayAll() client = SmtpRelayClient('addr', queue, socket_creator=self._socket_creator, ehlo_as='test', idle_timeout=0.0) client._run() self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result1.get_nowait()) self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result2.get_nowait())
def test_deliver_conversion_failure(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test \x81\r\n') self.sock.sendall(b'EHLO test\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall(b'RSET\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.mox.ReplayAll() client = SmtpRelayClient('addr', self.queue, socket_creator=self._socket_creator, ehlo_as='test') client._connect() client._ehlo() client._deliver(result, env) with self.assertRaises(PermanentRelayError): result.get_nowait()
def test_run_banner_failure(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test\r\n') queue = BlockingDeque() queue.append((result, env)) self.sock.recv(IsA(int)).AndReturn(b'520 Not Welcome\r\n') self.sock.sendall(b'QUIT\r\n') self.sock.recv(IsA(int)).AndReturn(b'221 Goodbye\r\n') self.sock.close() self.mox.ReplayAll() client = SmtpRelayClient('addr', queue, socket_creator=self._socket_creator, ehlo_as='test') client._run() with self.assertRaises(PermanentRelayError): result.get_nowait()
def test_run(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test\r\n') queue = BlockingDeque() queue.append((result, env)) self.sock.recv(IsA(int)).AndReturn(b'220 Welcome\r\n') self.sock.sendall(b'EHLO there\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall( b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n' ) self.sock.recv( IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n') self.sock.sendall( b'From: [email protected]\r\n\r\ntest test\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall(b'QUIT\r\n') self.sock.recv(IsA(int)).AndReturn(b'221 Goodbye\r\n') self.sock.close() self.mox.ReplayAll() client = SmtpRelayClient(('addr', 0), queue, socket_creator=self._socket_creator, ehlo_as='there') client._run() self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result.get_nowait())
def test_deliver_conversion(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test \x81\r\n') self.sock.sendall(b'EHLO there\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall( b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n' ) self.sock.recv( IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n') if pycompat.PY3: self.sock.sendall( b'From: [email protected]\r\nContent-Transfer-Encoding: base64\r\n\r\ndGVzdCB0ZXN0IIEK\r\n.\r\n' ) else: self.sock.sendall( b'From: [email protected]\r\nContent-Transfer-Encoding: base64\r\n\r\ndGVzdCB0ZXN0IIENCg==\r\n.\r\n' ) self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.mox.ReplayAll() client = SmtpRelayClient(('addr', 0), self.queue, socket_creator=self._socket_creator, ehlo_as='there', binary_encoder=encode_base64) client._connect() client._ehlo() client._deliver(result, env) self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result.get_nowait())
def test_deliver(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test \x81\r\n') self.sock.sendall(b'EHLO there\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 8BITMIME\r\n') self.sock.sendall(b'MAIL FROM:<*****@*****.**>\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall(b'RCPT TO:<*****@*****.**>\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall(b'DATA\r\n') self.sock.recv(IsA(int)).AndReturn(b'354 Go ahead\r\n') self.sock.sendall( b'From: [email protected]\r\n\r\ntest test \x81\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.mox.ReplayAll() client = SmtpRelayClient(('addr', 0), self.queue, socket_creator=self._socket_creator, ehlo_as='there') client._connect() client._ehlo() client._deliver(result, env) self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result.get_nowait())
def test_run_random_exception(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test\r\n') queue = BlockingDeque() queue.append((result, env)) self.sock.recv(IsA(int)).AndRaise(ValueError('test error')) self.sock.sendall(b'QUIT\r\n') self.sock.recv(IsA(int)).AndReturn(b'221 Goodbye\r\n') self.sock.close() self.mox.ReplayAll() client = SmtpRelayClient('addr', queue, socket_creator=self._socket_creator, ehlo_as='test') with self.assertRaises(ValueError): client._run() with self.assertRaises(ValueError): result.get_nowait()
def test_deliver_badrcpts(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test\r\n') self.sock.sendall(b'EHLO test\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall(b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n550 Not ok\r\n354 Go ahead\r\n') self.sock.sendall(b'.\r\nRSET\r\n') self.sock.recv(IsA(int)).AndReturn(b'550 Yikes\r\n250 Ok\r\n') self.mox.ReplayAll() client = SmtpRelayClient('addr', self.queue, socket_creator=self._socket_creator, ehlo_as='test') client._connect() client._ehlo() client._deliver(result, env) with self.assertRaises(PermanentRelayError): result.get_nowait()
def test_run_smtperror(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test\r\n') queue = BlockingDeque() queue.append((result, env)) self.sock.recv(IsA(int)).AndRaise(SmtpError('test error')) self.sock.sendall(b'QUIT\r\n') self.sock.recv(IsA(int)).AndReturn(b'221 Goodbye\r\n') self.sock.close() self.mox.ReplayAll() client = SmtpRelayClient('addr', queue, socket_creator=self._socket_creator, ehlo_as='test') client._run() with self.assertRaises(TransientRelayError): result.get_nowait()
def test_deliver_conversion_failure(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test \x81\r\n') self.sock.sendall(b'EHLO there\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall(b'RSET\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.mox.ReplayAll() client = SmtpRelayClient(('addr', 0), self.queue, socket_creator=self._socket_creator, ehlo_as='there') client._connect() client._ehlo() client._deliver(result, env) with self.assertRaises(PermanentRelayError): result.get_nowait()
def test_deliver_rset_exception(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test\r\n') self.sock.sendall(b'EHLO test\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall(b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n450 No!\r\n') self.sock.sendall(b'RSET\r\n') self.sock.recv(IsA(int)).AndRaise(ConnectionLost) self.mox.ReplayAll() client = SmtpRelayClient('addr', self.queue, socket_creator=self._socket_creator, ehlo_as='test') client._connect() client._ehlo() with self.assertRaises(ConnectionLost): client._deliver(result, env) with self.assertRaises(TransientRelayError): result.get_nowait()
def test_run_banner_failure(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test\r\n') queue = BlockingDeque() queue.append((result, env)) self.sock.recv(IsA(int)).AndReturn(b'520 Not Welcome\r\n') self.sock.sendall(b'QUIT\r\n') self.sock.recv(IsA(int)).AndReturn(b'221 Goodbye\r\n') self.sock.close() self.mox.ReplayAll() client = SmtpRelayClient(('addr', 0), queue, socket_creator=self._socket_creator, ehlo_as='there') client._run() with self.assertRaises(PermanentRelayError): result.get_nowait()
def test_run_multiple(self): result1 = AsyncResult() result2 = AsyncResult() env1 = Envelope('*****@*****.**', ['*****@*****.**']) env1.parse(b'From: [email protected]\r\n\r\ntest test\r\n') env2 = Envelope('*****@*****.**', ['*****@*****.**']) env2.parse(b'From: [email protected]\r\n\r\ntest test\r\n') queue = BlockingDeque() queue.append((result1, env1)) queue.append((result2, env2)) self.sock.recv(IsA(int)).AndReturn(b'220 Welcome\r\n') self.sock.sendall(b'EHLO test\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall( b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n' ) self.sock.recv( IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n') self.sock.sendall( b'From: [email protected]\r\n\r\ntest test\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall( b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n' ) self.sock.recv( IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n') self.sock.sendall( b'From: [email protected]\r\n\r\ntest test\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall(b'QUIT\r\n') self.sock.recv(IsA(int)).AndReturn(b'221 Goodbye\r\n') self.sock.close() self.mox.ReplayAll() client = SmtpRelayClient('addr', queue, socket_creator=self._socket_creator, ehlo_as='test', idle_timeout=0.0) client._run() self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result1.get_nowait()) self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result2.get_nowait())
def test_deliver_conversion(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test \x81\r\n') self.sock.sendall(b'EHLO test\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall(b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n') self.sock.sendall(b'From: [email protected]\r\nContent-Transfer-Encoding: base64\r\n\r\ndGVzdCB0ZXN0IIENCg==\n\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.mox.ReplayAll() client = SmtpRelayClient('addr', self.queue, socket_creator=self._socket_creator, ehlo_as='test', binary_encoder=encode_base64) client._connect() client._ehlo() client._deliver(result, env) self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result.get_nowait())
def test_run(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test\r\n') queue = BlockingDeque() queue.append((result, env)) self.sock.recv(IsA(int)).AndReturn(b'220 Welcome\r\n') self.sock.sendall(b'EHLO there\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n') self.sock.sendall(b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n') self.sock.sendall(b'From: [email protected]\r\n\r\ntest test\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall(b'QUIT\r\n') self.sock.recv(IsA(int)).AndReturn(b'221 Goodbye\r\n') self.sock.close() self.mox.ReplayAll() client = SmtpRelayClient(('addr', 0), queue, socket_creator=self._socket_creator, ehlo_as='there') client._run() self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result.get_nowait())
def test_deliver(self): result = AsyncResult() env = Envelope('*****@*****.**', ['*****@*****.**']) env.parse(b'From: [email protected]\r\n\r\ntest test \x81\r\n') self.sock.sendall(b'EHLO test\r\n') self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 8BITMIME\r\n') self.sock.sendall(b'MAIL FROM:<*****@*****.**>\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall(b'RCPT TO:<*****@*****.**>\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.sock.sendall(b'DATA\r\n') self.sock.recv(IsA(int)).AndReturn(b'354 Go ahead\r\n') self.sock.sendall(b'From: [email protected]\r\n\r\ntest test \x81\r\n.\r\n') self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n') self.mox.ReplayAll() client = SmtpRelayClient('addr', self.queue, socket_creator=self._socket_creator, ehlo_as='test') client._connect() client._ehlo() client._deliver(result, env) self.assertEqual({'*****@*****.**': Reply('250', 'Ok')}, result.get_nowait())
class MessageChannel(Channel): """A channel that adds useful semantics for publishing and consuming messages. Semantics that are added: * Support for registering consumers to receive basic.deliver events. Consumers also receive errors and are automatically deregistered when basic_cancel is received. * Support for the RabbitMQ extension confirm_select, which makes basic_publish block * Can check for messages returned with basic_return """ def __init__(self, connection, id): super(MessageChannel, self).__init__(connection, id) self.consumer_id = 1 self.consumers = {} self.returned = AsyncResult() self.listeners.set_handler('basic.deliver', self.on_deliver) self.listeners.set_handler('basic.return', self.on_basic_return) self.listeners.set_handler('basic.cancel-ok', self.on_cancel_ok) self.listeners.set_handler('basic.cancel', self.on_cancel_ok) def on_deliver(self, message): """Called when a message is received. Dispatches the message to the registered consumer. """ self.consumers[message.consumer_tag](message) def on_basic_return(self, msg): """When we receive a basic.return message, store it. The value can later be checked using .check_returned(). """ self.returned.set(msg) def check_returned(self): """Raise an error if a message has been returned. This also clears the returned frame, with the intention that each basic.return message may cause at most one MessageReturned error. """ if self._method and self._method.name == 'basic.return': self.must_now_block() returned = self.returned.get() else: try: returned = self.returned.get_nowait() except gevent.Timeout: return self.clear_returned() if returned: raise exceptions.return_exception_from_frame(returned) def clear_returned(self): """Discard any returned message.""" if self.returned.ready(): # we can only replace returned if it is ready - otherwise anything # that was blocked waiting would wait forever. self.returned = AsyncResult() def on_error(self, exc): """Override on_error, to pass error to all consumers.""" for consumer in self.consumers.values(): self.queue.put((consumer, (exc, ))) super(MessageChannel, self).on_error(exc) def on_cancel_ok(self, frame): """The server has cancelled a consumer. We can remove its consumer tag from the registered consumers.""" del (self.consumers[frame.consumer_tag]) def basic_consume(self, queue='', no_local=False, no_ack=False, exclusive=False, arguments={}, callback=None): """Begin consuming messages from a queue. Consumers last as long as the channel they were declared on, or until the client cancels them. :param queue: Specifies the name of the queue to consume from. :param no_local: Do not deliver own messages. If this flag is set the server will not send messages to the connection that published them. :param no_ack: Don't require acknowledgements. If this flag is set the server does not expect acknowledgements for messages. That is, when a message is delivered to the client the server assumes the delivery will succeed and immediately dequeues it. This functionality may increase performance but at the cost of reliability. Messages can get lost if a client dies before they are delivered to the application. :param exclusive: Request exclusive consumer access, meaning only this consumer can access the queue. :param arguments: A set of arguments for the consume. The syntax and semantics of these arguments depends on the server implementation. :param callback: A callback to be called for each message received. """ tag = 'ct-%d' % self.consumer_id self.consumer_id += 1 kwargs = dict(queue=queue, no_local=no_local, no_ack=no_ack, exclusive=exclusive, arguments=arguments, consumer_tag=tag) if callback is not None: self.consumers[tag] = callback return super(MessageChannel, self).basic_consume(**kwargs) else: queue = MessageQueue(self, tag) self.consumers[tag] = queue.put super(MessageChannel, self).basic_consume(**kwargs) return queue def basic_get(self, *args, **kwargs): """Wrap basic_get to return None if the response is basic.get-empty. This will be easier for users to check than testing whether a response is get-empty. """ r = super(MessageChannel, self).basic_get(*args, **kwargs) return r if isinstance(r, Message) else None def confirm_select(self, nowait=False): """Turn on RabbitMQ's publisher acknowledgements. See http://www.rabbitmq.com/confirms.html There are two things that need to be done: * Swap basic_publish to a version that blocks waiting for the corresponding ack. * Support nowait (because this method blocks or not depending on that argument) """ self.basic_publish = self.basic_publish_with_confirm if nowait: super(MessageChannel, self).confirm_select(nowait=nowait) else: # Send frame directly, as no callback will be received self._send(spec.FrameConfirmSelect(1)) def basic_publish_with_confirm(self, exchange='', routing_key='', mandatory=False, immediate=False, headers={}, body=''): """Version of basic publish that blocks waiting for confirm.""" method = super(MessageChannel, self).basic_publish self.clear_returned() ret = self._call_sync(method, ('basic.ack', 'basic.nack'), exchange, routing_key, mandatory, immediate, headers, body) if ret.name == 'basic.nack': raise exceptions.PublishFailed(ret) if mandatory or immediate: self.check_returned() return ret