2008-12-09 11 views
10

Je suis curieux de savoir s'il existe un moyen facile de se moquer d'un serveur IMAP (un la le module imaplib) en Python, sans faire beaucoup de travail.Comment se moquer d'un serveur IMAP en Python, malgré une extrême paresse?

Existe-t-il une solution préexistante? Idéalement, je pourrais me connecter au serveur IMAP existant, effectuer un vidage et faire en sorte que le serveur fictif s'exécute sur la structure réelle de la boîte aux lettres/courrier électronique.

Un peu d'histoire dans la paresse: j'ai le sentiment désagréable que ce petit script que je suis écriture va croître au fil du temps et se comme pour créer un environnement de test approprié, mais étant donné qu'il pourrait pas croître au fil du temps , Je ne veux pas faire beaucoup de travail pour faire fonctionner le faux serveur.

Répondre

9

Je l'ai trouvé assez facile d'écrire un serveur IMAP dans la dernière fois que j'ai essayé. Il est compatible avec l'écriture de serveurs IMAP et vous disposez d'une grande flexibilité.

1

Je n'ai jamais essayé, mais si je devais le faire, je commencerais par le serveur SMTP existant.

+1

Lien ci-dessus est mort, un nouveau est susceptible https://docs.python.org/2/library/smtpd.html – sdaau

7

De combien avez-vous vraiment besoin pour un test? Si vous commencez à construire quelque chose selon l'ordre de complexité d'un vrai serveur pour pouvoir l'utiliser sur tous vos tests, vous vous êtes déjà trompé. Il suffit de se moquer des bits dont on a besoin.

Ne vous embêtez pas à essayer de partager une implémentation fictive. Ils ne sont pas censés être des atouts, mais des morceaux-n-pièces jetables.

3

Comme je ne l'ai pas trouvé quelque chose commode en python 3 pour mes besoins (partie du courrier de tordu n'est pas en cours d'exécution en python 3), j'ai fait une petite maquette avec asyncio que vous pouvez améliorer si vous le souhaitez:

J'ai défini un ImapProtocol qui étend asyncio.Protocol. Ensuite, lancez un serveur comme ceci:

factory = loop.create_server(lambda: ImapProtocol(mailbox_map), 'localhost', 1143) 
server = loop.run_until_complete(factory) 

Le mailbox_map est une carte de carte: email -> carte des boîtes aux lettres -> ensemble de messages. Donc, tous les messages/boîtes aux lettres sont en mémoire.

Chaque fois qu'un client se connecte, une nouvelle instance de ImapProtocol est créée. Ensuite, les exécute de ImapProtocol et des réponses pour chaque client, la capacité de mise en œuvre/connexion/fetch/select/Recherche/magasin:

class ImapHandler(object): 
    def __init__(self, mailbox_map): 
     self.mailbox_map = mailbox_map 
     self.user_login = None 
     # ... 

    def connection_made(self, transport): 
     self.transport = transport 
     transport.write('* OK IMAP4rev1 MockIMAP Server ready\r\n'.encode()) 

    def data_received(self, data): 
     command_array = data.decode().rstrip().split() 
     tag = command_array[0] 
     self.by_uid = False 
     self.exec_command(tag, command_array[1:]) 

    def connection_lost(self, error): 
     if error: 
      log.error(error) 
     else: 
      log.debug('closing') 
      self.transport.close() 
     super().connection_lost(error) 

    def exec_command(self, tag, command_array): 
     command = command_array[0].lower() 
     if not hasattr(self, command): 
      return self.error(tag, 'Command "%s" not implemented' % command) 
     getattr(self, command)(tag, *command_array[1:]) 

    def capability(self, tag, *args): 
     # code for it... 
    def login(self, tag, *args): 
     # code for it... 

Puis dans mes tests, je commence le serveur lors de l'installation avec:

self.loop = asyncio.get_event_loop() 
self.server = self.loop.run_until_complete(self.loop.create_server(create_imap_protocol, 'localhost', 12345)) 

Quand je veux simuler un nouveau message:

imap_receive(Mail(to='[email protected]', mail_from='[email protected]', subject='hello')) 

Et l'arrêter à teardown:

self.server.close() 
asyncio.wait_for(self.server.wait_closed(), 1) 

cf https://github.com/bamthomas/aioimaplib/blob/master/aioimaplib/tests/imapserver.py


EDIT: J'ai eu un arrêt buggy du serveur, je réécris avec asyncio.Protocole et modifier la réponse pour refléter les changements

+0

Bien que ce lien peut répondre à la question, il est préférable pour inclure les parties essentielles de la réponse ici et fournir le lien pour référence. Les réponses à lien uniquement peuvent devenir invalides si la page liée change. - [De l'examen] (/ review/low-quality-posts/11319593) – jezrael

+0

Ok, je le fais –

+0

Mais était-il nécessaire de voter en bas ce sérieux? Tu sais que je m'en fous, je ne suis pas le genre de gars qui se précipite après les points SO (as-tu vu mon score?) Mais j'essayais d'aider les gens quand je rencontrais un problème qui me faisait perdre mon temps. Je n'étais pas obligé de pousser mon code sur github et de donner cette réponse. Ce genre d'action me pousse sérieusement à cesser d'utiliser SO. Mes 2 cents –