Merge "[tempestmail] Custom email for different matchers"

This commit is contained in:
Zuul 2018-01-09 19:13:51 +00:00 committed by Gerrit Code Review
commit 9092591efe
3 changed files with 85 additions and 23 deletions

View File

@ -96,6 +96,26 @@ gate-tripleo-ci-centos-7-ovb-ha-oooq or
gate-tripleo-ci-centos-7-ovb-containers-oooq has a test failure that matches gate-tripleo-ci-centos-7-ovb-containers-oooq has a test failure that matches
the regex. the regex.
```yaml
...
emails:
- mail: fail1@example.com
regex: '.*foo.*'
topics: foo1
- mail: fail1@example.com
regex: '.*bar.*'
topics: bar1
- mail: fail2@example.com
regex: '.*bar.*'
topics: bar2,extra
...
```
if a jobs contains tests matching both 'foo' and 'bar', then:
* fail1@ will receive an email '[foo1]...' and an email '[bar1]...'
* fail2@ will receive an email '[bar2][extra]...'
So, the order is: So, the order is:
1. If there's no jobs list the user will receive all the emails. 1. If there's no jobs list the user will receive all the emails.

View File

@ -108,7 +108,7 @@ class Mail(object):
def filter_emails(self, job, data): def filter_emails(self, job, data):
has_errors = False has_errors = False
addresses = [] bookaddr = {}
for error in [data.get(x, []) for x in ('new', 'failed', 'errors')]: for error in [data.get(x, []) for x in ('new', 'failed', 'errors')]:
if error: if error:
@ -123,24 +123,33 @@ class Mail(object):
m.get('jobs') or not m.get('jobs') or not
m.get('jobs')] m.get('jobs')]
# Now we filter for regex if doesn't exists # Add all addresses except those that regex don't match
addresses = [m.get('mail') for m in emails if not m.get('regex')]
# And finally, if regex exists
for email in emails: for email in emails:
for r in email.get('regex'): add = True
if len(filter(r.search, data.get('new'))): if email.get('regex'):
addresses.append(email.get('mail')) for r in email.get('regex'):
break if len(filter(r.search, data.get('new'))):
break
add = False
if add:
topics = ''
if email.get('topics'):
# Parse topics and format it between brackets
t = email.get('topics').split(',')
topics = ''.join('[{}]'.format(s) for s in t)
# Add the address to the bookaddr dict
# {'[foo][bar]' : ['john@redhat.com', 'mary@redhat.com']}
bookaddr.setdefault(topics, []).append(email.get('mail'))
else: else:
self.log.debug('No failures send email to everybody') self.log.debug('No failures send email to everybody')
addresses = [m.get('mail') for m in self.config.emails addresses = [m.get('mail') for m in self.config.emails
if not m.get('fail_only')] if not m.get('fail_only')]
# Single group with empty topic is added to the bookaddr
bookaddr.setdefault('', []).append(addresses)
data['has_errors'] = has_errors data['has_errors'] = has_errors
return addresses return bookaddr
def _send_mail_local(self, addresses, message, subject, output): def _send_mail_local(self, addresses, message, subject, output):
msg = MIMEText(message, 'html') msg = MIMEText(message, 'html')
@ -167,14 +176,16 @@ class Mail(object):
requests.post(self.config.api_server, data=data) requests.post(self.config.api_server, data=data)
def send_mail(self, job, data, output): def send_mail(self, job, data, output):
addresses = self.filter_emails(job, data) bookaddr = self.filter_emails(job, data)
message = self.render_template(data) message = self.render_template(data)
subject = 'Job {} results'.format(job)
if self.config.use_api_server: # Send a separate email to the addresses grouped by topics
self._send_mail_api(addresses, message, subject) for topics, addresses in bookaddr.items():
else: subject = '{} Job {} results'.format(topics, job).lstrip()
self._send_mail_local(addresses, message, subject, output) if self.config.use_api_server:
self._send_mail_api(addresses, message, subject)
else:
self._send_mail_local(addresses, message, subject, output)
class TempestMailCmd(object): class TempestMailCmd(object):
@ -367,6 +378,7 @@ class TempestMailCmd(object):
'mail': e.get('mail'), 'mail': e.get('mail'),
'jobs': e.get('jobs', []), 'jobs': e.get('jobs', []),
'regex': regex, 'regex': regex,
'topics': e.get('topics'),
'fail_only': e.get('fail_only', False)}) 'fail_only': e.get('fail_only', False)})
for t in config.get('known_failures', []): for t in config.get('known_failures', []):
known_failures.append({'test': t.get('test'), known_failures.append({'test': t.get('test'),

View File

@ -2,6 +2,7 @@ import datetime
import mock import mock
import tempfile import tempfile
import unittest import unittest
import re
from tempestmail import Config from tempestmail import Config
from tempestmail import Mail from tempestmail import Mail
@ -29,9 +30,9 @@ class MailTest(unittest.TestCase):
config.require_auth = True config.require_auth = True
config.emails = [ config.emails = [
{'mail': 'email1@example.com', 'name': 'name 1', {'mail': 'email1@example.com', 'name': 'name 1',
'jobs': [], 'regex': []}, 'jobs': [], 'regex': [], 'topics': ''},
{'mail': 'email2@example.com', 'name': 'name 2', {'mail': 'email2@example.com', 'name': 'name 2',
'jobs': [], 'regex': []} 'jobs': [], 'regex': [], 'topics': ''}
] ]
config.template = 'template.html' config.template = 'template.html'
return config return config
@ -87,16 +88,45 @@ class MailTest(unittest.TestCase):
self.assertEquals(self.data.get('has_errors'), None) self.assertEquals(self.data.get('has_errors'), None)
addresses = mail.filter_emails( addresses = mail.filter_emails(
'periodic-tripleo-ci-centos-7-ovb-ha-tempest', self.data) 'periodic-tripleo-ci-centos-7-ovb-ha-tempest', self.data)
self.assertEquals(['email1@example.com', 'email2@example.com'], self.assertEquals({'' : ['email1@example.com', 'email2@example.com']},
addresses) addresses)
mail.config.emails[0]['jobs'].append('another-job') mail.config.emails[0]['jobs'].append('another-job')
addresses = mail.filter_emails( addresses = mail.filter_emails(
'periodic-tripleo-ci-centos-7-ovb-ha-tempest', self.data) 'periodic-tripleo-ci-centos-7-ovb-ha-tempest', self.data)
self.assertEquals(['email2@example.com'], addresses) self.assertEquals({'' : ['email2@example.com']}, addresses)
self.assertEquals(self.data['has_errors'], True) self.assertEquals(self.data['has_errors'], True)
mail.config.emails[0]['jobs'] = [] mail.config.emails[0]['jobs'] = []
mail.config.emails[0]['regex'].append('tempest.some.regex') mail.config.emails[0]['regex'].append(re.compile(
self.assertEquals(['email2@example.com'], addresses) 'tempest.some.regex'))
self.assertEquals({'' : ['email2@example.com']}, addresses)
def test_filter_emails_topics(self):
mail = Mail(self.config)
addresses = mail.filter_emails(
'periodic-tripleo-ci-centos-7-ovb-ha-tempest', self.data)
self.assertEquals({'' : ['email1@example.com',
'email2@example.com']},
addresses)
mail.config.emails[0]['jobs'].append(
'periodic-tripleo-ci-centos-7-ovb-ha-tempest')
mail.config.emails[0]['regex'].append(re.compile(
'upload_too_many_objects'))
mail.config.emails[0]['topics'] = 'many_objects'
mail.config.emails[1]['regex'].append(re.compile(
'upload_valid_object'))
mail.config.emails[1]['topics'] = 'valid_object'
new = {'mail': 'email2@example.com', 'name': 'name 2',
'jobs': ['periodic-tripleo-ci-centos-7-ovb-ha-tempest'],
'regex': [re.compile('upload_valid_object')],
'topics': 'valid_object,object_storage'}
mail.config.emails.append(new)
addresses = mail.filter_emails(
'periodic-tripleo-ci-centos-7-ovb-ha-tempest', self.data)
bookaddr = {'[many_objects]' : ['email1@example.com'],
'[valid_object]' : ['email2@example.com'],
'[valid_object][object_storage]' : ['email2@example.com']
}
self.assertEquals(bookaddr, addresses)
@mock.patch('tempestmail.Mail._send_mail_api') @mock.patch('tempestmail.Mail._send_mail_api')
@mock.patch('tempestmail.Mail._send_mail_local') @mock.patch('tempestmail.Mail._send_mail_local')