Skip to content

Commit 7b0193b

Browse files
committed
Expose email send as an assistant and provide its fake in the test suite.
Use the runtime configuration concept to expose the sending of email to logic codepaths. This avoids adding an argument at multiple levels of the call stack of logic code purely to override email sending. As a result, we are able to centrally intercept email sending. Do this, and as a consequence sprinkle a bunch of additional assertions into calls that happen to send email but this side-effect was completely uncovered. Add a means for tests to check the the number of emails sent and whether an email was sent to a particular recipient. For cases where the email sent is not relevant to what is being tested, there is an escape hatch.
1 parent 0f6ad3e commit 7b0193b

16 files changed

Lines changed: 177 additions & 41 deletions

mig/server/grid_notify.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,10 @@ def send_notifications(configuration):
130130
notify_message = "Found %s new events since: %s\n\n" \
131131
% (total_events, timestr) \
132132
+ notify_message
133-
status = send_email(
133+
status = configuration.send_email(
134134
recipient,
135135
subject,
136-
notify_message,
137-
logger,
138-
configuration)
136+
notify_message)
139137
if status:
140138
logger.info("Send email with %s events to: %s"
141139
% (total_events, recipient))

mig/shared/conf.py

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@
3737
from mig.shared.fileio import unpickle
3838

3939

40+
_RUNTIME_ASSISTANTS = {
41+
'send_email': None,
42+
}
43+
44+
45+
def default_runtime_assistants():
46+
runtime_services = dict(_RUNTIME_ASSISTANTS)
47+
48+
from mig.shared.notification import send_email
49+
runtime_services['send_email'] = send_email
50+
51+
return runtime_services
52+
53+
4054
class RuntimeConfiguration:
4155
"""A proxy object to be passed in-place of a Configuration which can be
4256
extended with information relevant only at runtime.
@@ -52,8 +66,9 @@ class RuntimeConfiguration:
5266
to callers without being mixed in with the statuc data.
5367
"""
5468

55-
def __init__(self, configuration):
69+
def __init__(self, configuration, assistants):
5670
object.__setattr__(self, '_configuration', configuration)
71+
object.__setattr__(self, '_assistants', assistants)
5772

5873
def __delattr__(self, attr):
5974
return setattr(self._configuration, attr)
@@ -64,9 +79,32 @@ def __getattr__(self, attr):
6479
def __setattr__(self, attr, value):
6580
return setattr(self._configuration, attr, value)
6681

82+
def get_assistant(self, assistant_name):
83+
return self._assistants[assistant_name]
84+
85+
def send_email(self, *args, **kwargs):
86+
send_email = self._assistants['send_email']
87+
return send_email(self, *args, **kwargs)
6788

68-
def get_configuration_object(config_file=None, skip_log=False,
69-
disable_auth_log=False):
89+
@classmethod
90+
def create(cls, configuration, assistants):
91+
supplied_assistants = set(assistants.keys())
92+
expected_assistants = set(_RUNTIME_ASSISTANTS.keys())
93+
94+
missing_assistants = expected_assistants - supplied_assistants
95+
if missing_assistants:
96+
raise RuntimeError('missing runtime assistants: %s'
97+
% (missing_assistants,))
98+
99+
return cls(configuration, assistants)
100+
101+
@staticmethod
102+
def default_assistants():
103+
return default_runtime_assistants()
104+
105+
106+
def get_configuration_object(config_file=None,
107+
skip_log=False, disable_auth_log=False, raw=False):
70108
"""Simple helper to call the general configuration init. Optional skip_log
71109
and disable_auth_log arguments are passed on to allow skipping the default
72110
log initialization and disabling auth log for unit tests.
@@ -93,7 +131,12 @@ def get_configuration_object(config_file=None, skip_log=False,
93131

94132
configuration = Configuration(_config_file, False, skip_log,
95133
disable_auth_log)
96-
return RuntimeConfiguration(configuration)
134+
135+
if raw:
136+
return configuration
137+
138+
assistants = RuntimeConfiguration.default_assistants()
139+
return RuntimeConfiguration(configuration, assistants)
97140

98141

99142
def get_resource_configuration(resource_home, unique_resource_name,

mig/shared/configuration.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2921,6 +2921,10 @@ def parse_peers(self, peerfile):
29212921
peerfile)
29222922
return peers_dict
29232923

2924+
@classmethod
2925+
def create(cls, *args, **kwargs):
2926+
return cls(*args, **kwargs)
2927+
29242928
@staticmethod
29252929
def is_configuration_like(obj):
29262930
"""Does the given object quack like a MiG Configuration."""

mig/shared/functionality/autocreate.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -740,8 +740,7 @@ def main(client_id, user_arguments_dict, environ=None):
740740
logger.info('Send email: to: %s, header: %s, smtp_server: %s'
741741
% (email, email_header, smtp_server))
742742
logger.debug('email body: %s' % email_msg)
743-
if not send_email(email, email_header, email_msg, logger,
744-
configuration):
743+
if not configuration.send_email(email, email_header, email_msg):
745744
output_objects.append({
746745
'object_type': 'error_text', 'text': """An error occurred trying
747746
to send your account welcome email. Please contact support (%s) and include the

mig/shared/functionality/extcertaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,7 @@ def main(client_id, user_arguments_dict):
316316

317317
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
318318
% (admin_email, email_header, email_msg, smtp_server))
319-
if not send_email(admin_email, email_header, email_msg, logger,
320-
configuration):
319+
if not configuration.send_email(admin_email, email_header, email_msg):
321320
output_objects.append({'object_type': 'error_text', 'text':
322321
"""An error occurred trying to inform the site
323322
admins about your request for existing certificate sign up. Please contact %s site

mig/shared/functionality/extoidaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,7 @@ def main(client_id, user_arguments_dict):
282282

283283
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
284284
% (admin_email, email_header, email_msg, smtp_server))
285-
if not send_email(admin_email, email_header, email_msg, logger,
286-
configuration):
285+
if not configuration.send_email(admin_email, email_header, email_msg):
287286
output_objects.append({'object_type': 'error_text', 'text':
288287
"""An error occurred trying to inform the site
289288
admins about your request for OpenID account access. Please contact %s site

mig/shared/functionality/peersaction.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,7 @@ def main(client_id, user_arguments_dict):
309309
logger.info('Sending invitation: to: %s, header: %s, msg: %s, smtp_server: %s'
310310
% (peer_email, email_header, email_msg,
311311
smtp_server))
312-
if send_email(peer_email, email_header, email_msg, logger,
313-
configuration):
312+
if configuration.send_email(peer_email, email_header, email_msg):
314313
succeeded.append(peer_email)
315314
else:
316315
failed.append(peer_email)
@@ -369,8 +368,7 @@ def main(client_id, user_arguments_dict):
369368

370369
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
371370
% (admin_email, email_header, email_msg, smtp_server))
372-
if not send_email(admin_email, email_header, email_msg, logger,
373-
configuration):
371+
if not configuration.send_email(admin_email, email_header, email_msg):
374372
output_objects.append({'object_type': 'error_text', 'text': '''
375373
An error occurred trying to send the email about your %s peers to the site
376374
administrators. Please contact %s site support at %s or manually inform the

mig/shared/functionality/reqcertaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,7 @@ def main(client_id, user_arguments_dict):
346346

347347
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
348348
% (admin_email, email_header, email_msg, smtp_server))
349-
if not send_email(admin_email, email_header, email_msg, logger,
350-
configuration):
349+
if not configuration.send_email(admin_email, email_header, email_msg):
351350
output_objects.append({'object_type': 'error_text', 'text':
352351
"""An error occurred trying to inform the site
353352
admins about your request for certificate sign up. Please contact %s site

mig/shared/functionality/reqoidaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,7 @@ def main(client_id, user_arguments_dict):
357357

358358
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
359359
% (admin_email, email_header, email_msg, smtp_server))
360-
if not send_email(admin_email, email_header, email_msg, logger,
361-
configuration):
360+
if not configuration.send_email(admin_email, email_header, email_msg):
362361
output_objects.append({'object_type': 'error_text', 'text':
363362
"""An error occurred trying to inform the site
364363
admins about your request for OpenID account access. Please contact %s site

mig/shared/functionality/reqpwresetaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,7 @@ def main(client_id, user_arguments_dict):
271271

272272
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
273273
% (email_to, email_header, email_msg, smtp_server))
274-
if not send_email(email_to, email_header, email_msg, logger,
275-
configuration):
274+
if not configuration.send_email(email_to, email_header, email_msg):
276275
output_objects.append({'object_type': 'error_text', 'text':
277276
"""An error occurred trying to send the email
278277
for an account %s password reset request. Please contact %s site support at %s

0 commit comments

Comments
 (0)