from yaml import load, SafeLoader from os import environ import pytest import datetime from imaplib2 import IMAP4_SSL from smtplib import SMTP, SMTPNotSupportedError, SMTPAuthenticationError conf_file = f'{environ["MACHINE_TEST_DIR"]}/imap.yml' with open(conf_file) as yaml: data = load(yaml, Loader=SafeLoader) parameters = ( (1, 5, 'user', data['username'], data['username'], data['username'], [data['password']]), (2, 5, 'user', data['username'], data['username'], 'alias_' + data['username'], [data['password']]), (1, 3, 'family', data['username_family'], data['username_family'], data['username_family'], [data['password_family'], data['password_family'] + "2"]), (3, 5, 'user', data['username'], data['ext_username'], data['username'], [data['password']]), (4, 5, 'user', data['username'], data['ext_username'], 'alias_' + data['username'], [data['password']]), (2, 3, 'family', data['username_family'], data['ext_username'], data['username_family'], [data['password_family'], data['password_family'] + "2"]), ) def get_msg(username, dest, msg='MESSAGE', with_date=True): date = datetime.datetime.now() ret = f'From: {username}\r\nTo: {dest}\r\n\r\nSubject: TEST\r\n{msg}\r\n' if with_date: date_str = date.strftime('%a, %d %b %Y %H:%M:%S +0200 (CEST)') ret = f'Date: {date_str}\r\n{ret}' return ret @pytest.mark.parametrize('idx, maxi, typ, login_username, username, dest, passwords', parameters) def test_imap_wrong_password(idx, maxi, typ, login_username, username, dest, passwords): if username == data['ext_username']: return imap = IMAP4_SSL(data['address']) try: imap.LOGIN(username, 'b') except: pass else: raise Exception('wrong login !') @pytest.mark.parametrize('idx, maxi, typ, login_username, username, dest, passwords', parameters) def test_imap_migration(idx, maxi, typ, login_username, username, dest, passwords): if dest.startswith('alias_'): return if username == data['ext_username']: return msg = get_msg(username, dest, 'MIGRATION', False) if 'FIRST_RUN' in environ: smtp = SMTP(data['address'], '587') smtp.starttls() error = None for password in passwords: try: smtp.login(username, password) break except SMTPAuthenticationError as err: error = err else: raise error from error smtp.sendmail(username, dest, msg) smtp.quit() imap = IMAP4_SSL(data['address']) error = None for password in passwords: try: imap.LOGIN(username, password) break except Exception as err: error = err else: raise error from error imap.SELECT(readonly=True) typ, req = imap.SEARCH(None, 'ALL') assert typ == 'OK' assert len(req) == 1 assert req[0] == b'1' field = imap.FETCH('1', '(RFC822)') assert field[0] == 'OK' assert field[1][-2][-1].decode().endswith(msg) imap.CLOSE() imap.LOGOUT() @pytest.mark.parametrize('idx, maxi, typ, login_username, username, dest, passwords', parameters) def test_smtp_no_tls(idx, maxi, typ, login_username, username, dest, passwords): if username == data['ext_username']: return smtp = SMTP(data['address'], '587') with pytest.raises(SMTPNotSupportedError): smtp.login(username, passwords[0]) @pytest.mark.parametrize('idx, maxi, typ, login_username, username, dest, passwords', parameters) def test_smtp_wrong_passwd(idx, maxi, typ, login_username, username, dest, passwords): if username == data['ext_username']: return smtp = SMTP(data['address'], '587') smtp.starttls() with pytest.raises(SMTPAuthenticationError): smtp.login(username, 'a') smtp.quit() @pytest.mark.parametrize('idx, maxi, typ, login_username, username, dest, passwords', parameters) def test_smtp_login(idx, maxi, typ, login_username, username, dest, passwords): if username == data['ext_username']: return smtp = SMTP(data['address'], '587') smtp.starttls() error = None for password in passwords: try: smtp.login(username, password) break except SMTPAuthenticationError as err: error = err else: raise error from error smtp.quit() @pytest.mark.parametrize('idx, maxi, typ, login_username, username, dest, passwords', parameters) def test_smtp_sendmail(idx, maxi, typ, login_username, username, dest, passwords): if username == data['ext_username']: smtp = SMTP(data['smtp'], '25') else: smtp = SMTP(data['address'], '587') smtp.starttls() error = None for password in passwords: try: smtp.login(username, password) break except SMTPAuthenticationError as err: error = err else: raise error from error smtp.sendmail(username, dest, get_msg(username, dest)) smtp.quit() @pytest.mark.parametrize('idx, maxi, typ, login_username, username, dest, passwords', parameters) def test_imap_read_mail(idx, maxi, typ, login_username, username, dest, passwords): imap = IMAP4_SSL(data['address']) error = None for password in passwords: try: imap.LOGIN(login_username, password) break except Exception as err: error = err else: raise error from error imap.SELECT(readonly=True) typ, req = imap.SEARCH(None, 'ALL') assert typ == 'OK' assert len(req) == 1 msg = get_msg(username, dest, with_date=False) msg_no = req[0].split() assert len(msg_no) == maxi num = msg_no[idx] field = imap.FETCH(num, '(RFC822)') assert field[0] == 'OK' fdata = field[1][-2][-1].decode().split('\r\n') if fdata[-2].startswith('--'): fdata = fdata[:-2] fdata = '\r\n'.join(fdata) assert 'Undelivered' not in fdata assert fdata.endswith(msg) imap.CLOSE() imap.LOGOUT() @pytest.mark.parametrize('idx, maxi, typ, login_username, username, dest, passwords', parameters) def test_imap_delete_mail(idx, maxi, typ, login_username, username, dest, passwords): if username == data['ext_username']: return imap = IMAP4_SSL(data['address']) error = None for password in passwords: try: imap.LOGIN(login_username, password) break except Exception as err: error = err else: raise error from error imap.SELECT() typ, req = imap.SEARCH(None, 'ALL') msg_no = req[0].split() for num in msg_no[1:]: ret = imap.store(num, '+FLAGS', '\\Deleted') assert ret[0] == 'OK', f'error when deleting mail: {ret}' imap.expunge() imap.CLOSE() imap.LOGOUT()