mirror of
https://github.com/GSA/notifications-api.git
synced 2026-09-10 01:56:03 -04:00
Remove everything for the performance platform
We no longer will send them any stats so therefore don't need the code - the code to work out the nightly stats - the performance platform client - any configuration for the client - any nightly tasks that kick off the sending off the stats We will require a change in cronitor as we no longer will have this task run meaning we need to delete the cronitor check.
This commit is contained in:
@@ -35,9 +35,6 @@ from app.clients.cbc_proxy import CBCProxyClient
|
|||||||
from app.clients.document_download import DocumentDownloadClient
|
from app.clients.document_download import DocumentDownloadClient
|
||||||
from app.clients.email.aws_ses import AwsSesClient
|
from app.clients.email.aws_ses import AwsSesClient
|
||||||
from app.clients.email.aws_ses_stub import AwsSesStubClient
|
from app.clients.email.aws_ses_stub import AwsSesStubClient
|
||||||
from app.clients.performance_platform.performance_platform_client import (
|
|
||||||
PerformancePlatformClient,
|
|
||||||
)
|
|
||||||
from app.clients.sms.firetext import FiretextClient
|
from app.clients.sms.firetext import FiretextClient
|
||||||
from app.clients.sms.mmg import MMGClient
|
from app.clients.sms.mmg import MMGClient
|
||||||
|
|
||||||
@@ -66,7 +63,6 @@ encryption = Encryption()
|
|||||||
zendesk_client = ZendeskClient()
|
zendesk_client = ZendeskClient()
|
||||||
statsd_client = StatsdClient()
|
statsd_client = StatsdClient()
|
||||||
redis_store = RedisClient()
|
redis_store = RedisClient()
|
||||||
performance_platform_client = PerformancePlatformClient()
|
|
||||||
cbc_proxy_client = CBCProxyClient()
|
cbc_proxy_client = CBCProxyClient()
|
||||||
document_download_client = DocumentDownloadClient()
|
document_download_client = DocumentDownloadClient()
|
||||||
metrics = GDSMetrics()
|
metrics = GDSMetrics()
|
||||||
@@ -117,7 +113,6 @@ def create_app(application):
|
|||||||
notify_celery.init_app(application)
|
notify_celery.init_app(application)
|
||||||
encryption.init_app(application)
|
encryption.init_app(application)
|
||||||
redis_store.init_app(application)
|
redis_store.init_app(application)
|
||||||
performance_platform_client.init_app(application)
|
|
||||||
document_download_client.init_app(application)
|
document_download_client.init_app(application)
|
||||||
|
|
||||||
cbc_proxy_client.init_app(application)
|
cbc_proxy_client.init_app(application)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from notifications_utils.statsd_decorators import statsd
|
|||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
|
||||||
from app import notify_celery, performance_platform_client, zendesk_client
|
from app import notify_celery, zendesk_client
|
||||||
from app.aws import s3
|
from app.aws import s3
|
||||||
from app.celery.service_callback_tasks import (
|
from app.celery.service_callback_tasks import (
|
||||||
create_delivery_status_callback_data,
|
create_delivery_status_callback_data,
|
||||||
@@ -21,7 +21,7 @@ from app.dao.jobs_dao import (
|
|||||||
dao_get_jobs_older_than_data_retention,
|
dao_get_jobs_older_than_data_retention,
|
||||||
)
|
)
|
||||||
from app.dao.notifications_dao import (
|
from app.dao.notifications_dao import (
|
||||||
dao_get_total_notifications_sent_per_day_for_performance_platform,
|
dao_get_notifications_processing_time_stats,
|
||||||
dao_timeout_notifications,
|
dao_timeout_notifications,
|
||||||
delete_notifications_older_than_retention_by_type,
|
delete_notifications_older_than_retention_by_type,
|
||||||
)
|
)
|
||||||
@@ -38,7 +38,6 @@ from app.models import (
|
|||||||
FactProcessingTime,
|
FactProcessingTime,
|
||||||
Notification,
|
Notification,
|
||||||
)
|
)
|
||||||
from app.performance_platform import processing_time, total_sent_notifications
|
|
||||||
from app.utils import get_london_midnight_in_utc
|
from app.utils import get_london_midnight_in_utc
|
||||||
|
|
||||||
|
|
||||||
@@ -157,54 +156,6 @@ def timeout_notifications():
|
|||||||
raise NotificationTechnicalFailureException(message)
|
raise NotificationTechnicalFailureException(message)
|
||||||
|
|
||||||
|
|
||||||
@notify_celery.task(name='send-daily-performance-platform-stats')
|
|
||||||
@cronitor('send-daily-performance-platform-stats')
|
|
||||||
@statsd(namespace="tasks")
|
|
||||||
def send_daily_performance_platform_stats(date=None):
|
|
||||||
# date is a string in the format of "YYYY-MM-DD"
|
|
||||||
if date is None:
|
|
||||||
date = (datetime.utcnow() - timedelta(days=1)).date()
|
|
||||||
else:
|
|
||||||
date = datetime.strptime(date, "%Y-%m-%d").date()
|
|
||||||
|
|
||||||
if performance_platform_client.active:
|
|
||||||
|
|
||||||
send_total_sent_notifications_to_performance_platform(bst_date=date)
|
|
||||||
processing_time.send_processing_time_to_performance_platform(bst_date=date)
|
|
||||||
|
|
||||||
|
|
||||||
def send_total_sent_notifications_to_performance_platform(bst_date):
|
|
||||||
count_dict = total_sent_notifications.get_total_sent_notifications_for_day(bst_date)
|
|
||||||
start_time = get_london_midnight_in_utc(bst_date)
|
|
||||||
|
|
||||||
email_sent_count = count_dict['email']
|
|
||||||
sms_sent_count = count_dict['sms']
|
|
||||||
letter_sent_count = count_dict['letter']
|
|
||||||
|
|
||||||
current_app.logger.info(
|
|
||||||
"Attempting to update Performance Platform for {} with {} emails, {} text messages and {} letters"
|
|
||||||
.format(bst_date, email_sent_count, sms_sent_count, letter_sent_count)
|
|
||||||
)
|
|
||||||
|
|
||||||
total_sent_notifications.send_total_notifications_sent_for_day_stats(
|
|
||||||
start_time,
|
|
||||||
'sms',
|
|
||||||
sms_sent_count
|
|
||||||
)
|
|
||||||
|
|
||||||
total_sent_notifications.send_total_notifications_sent_for_day_stats(
|
|
||||||
start_time,
|
|
||||||
'email',
|
|
||||||
email_sent_count
|
|
||||||
)
|
|
||||||
|
|
||||||
total_sent_notifications.send_total_notifications_sent_for_day_stats(
|
|
||||||
start_time,
|
|
||||||
'letter',
|
|
||||||
letter_sent_count
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@notify_celery.task(name="delete-inbound-sms")
|
@notify_celery.task(name="delete-inbound-sms")
|
||||||
@cronitor("delete-inbound-sms")
|
@cronitor("delete-inbound-sms")
|
||||||
@statsd(namespace="tasks")
|
@statsd(namespace="tasks")
|
||||||
@@ -336,7 +287,7 @@ def save_daily_notification_processing_time(bst_date=None):
|
|||||||
|
|
||||||
start_time = get_london_midnight_in_utc(bst_date)
|
start_time = get_london_midnight_in_utc(bst_date)
|
||||||
end_time = get_london_midnight_in_utc(bst_date + timedelta(days=1))
|
end_time = get_london_midnight_in_utc(bst_date + timedelta(days=1))
|
||||||
result = dao_get_total_notifications_sent_per_day_for_performance_platform(start_time, end_time)
|
result = dao_get_notifications_processing_time_stats(start_time, end_time)
|
||||||
insert_update_processing_time(
|
insert_update_processing_time(
|
||||||
FactProcessingTime(
|
FactProcessingTime(
|
||||||
bst_date=bst_date,
|
bst_date=bst_date,
|
||||||
|
|||||||
142
app/commands.py
142
app/commands.py
@@ -18,9 +18,6 @@ from sqlalchemy.orm.exc import NoResultFound
|
|||||||
from app import db, encryption
|
from app import db, encryption
|
||||||
from app.aws import s3
|
from app.aws import s3
|
||||||
from app.celery.letters_pdf_tasks import get_pdf_for_templated_letter
|
from app.celery.letters_pdf_tasks import get_pdf_for_templated_letter
|
||||||
from app.celery.nightly_tasks import (
|
|
||||||
send_total_sent_notifications_to_performance_platform,
|
|
||||||
)
|
|
||||||
from app.celery.reporting_tasks import (
|
from app.celery.reporting_tasks import (
|
||||||
create_nightly_notification_status_for_day,
|
create_nightly_notification_status_for_day,
|
||||||
)
|
)
|
||||||
@@ -36,7 +33,6 @@ from app.dao.fact_billing_dao import (
|
|||||||
get_service_ids_that_need_billing_populated,
|
get_service_ids_that_need_billing_populated,
|
||||||
update_fact_billing,
|
update_fact_billing,
|
||||||
)
|
)
|
||||||
from app.dao.fact_processing_time_dao import insert_update_processing_time
|
|
||||||
from app.dao.jobs_dao import dao_get_job_by_id
|
from app.dao.jobs_dao import dao_get_job_by_id
|
||||||
from app.dao.organisation_dao import (
|
from app.dao.organisation_dao import (
|
||||||
dao_add_service_to_organisation,
|
dao_add_service_to_organisation,
|
||||||
@@ -70,21 +66,13 @@ from app.models import (
|
|||||||
SMS_TYPE,
|
SMS_TYPE,
|
||||||
Domain,
|
Domain,
|
||||||
EmailBranding,
|
EmailBranding,
|
||||||
FactProcessingTime,
|
|
||||||
LetterBranding,
|
LetterBranding,
|
||||||
Notification,
|
Notification,
|
||||||
Organisation,
|
Organisation,
|
||||||
Service,
|
Service,
|
||||||
User,
|
User,
|
||||||
)
|
)
|
||||||
from app.performance_platform.processing_time import (
|
from app.utils import DATETIME_FORMAT, get_london_midnight_in_utc
|
||||||
send_processing_time_for_start_and_end,
|
|
||||||
)
|
|
||||||
from app.utils import (
|
|
||||||
DATETIME_FORMAT,
|
|
||||||
get_london_midnight_in_utc,
|
|
||||||
get_midnight_for_day_before,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@click.group(name='command', help='Additional commands')
|
@click.group(name='command', help='Additional commands')
|
||||||
@@ -243,59 +231,6 @@ def fix_notification_statuses_not_in_sync():
|
|||||||
result = db.session.execute(subq_hist).fetchall()
|
result = db.session.execute(subq_hist).fetchall()
|
||||||
|
|
||||||
|
|
||||||
@notify_command()
|
|
||||||
@click.option('-s', '--start_date', required=True, help="start date inclusive", type=click_dt(format='%Y-%m-%d'))
|
|
||||||
@click.option('-e', '--end_date', required=True, help="end date inclusive", type=click_dt(format='%Y-%m-%d'))
|
|
||||||
def backfill_performance_platform_totals(start_date, end_date):
|
|
||||||
"""
|
|
||||||
Send historical total messages sent to Performance Platform.
|
|
||||||
|
|
||||||
WARNING: This does not overwrite existing data. You need to delete
|
|
||||||
the existing data or Performance Platform will double-count.
|
|
||||||
"""
|
|
||||||
|
|
||||||
delta = end_date - start_date
|
|
||||||
|
|
||||||
print('Sending total messages sent for all days between {} and {}'.format(start_date, end_date))
|
|
||||||
|
|
||||||
for i in range(delta.days + 1):
|
|
||||||
|
|
||||||
process_date = start_date + timedelta(days=i)
|
|
||||||
|
|
||||||
print('Sending total messages sent for {}'.format(
|
|
||||||
process_date.isoformat()
|
|
||||||
))
|
|
||||||
|
|
||||||
send_total_sent_notifications_to_performance_platform(process_date)
|
|
||||||
|
|
||||||
|
|
||||||
@notify_command()
|
|
||||||
@click.option('-s', '--start_date', required=True, help="start date inclusive", type=click_dt(format='%Y-%m-%d'))
|
|
||||||
@click.option('-e', '--end_date', required=True, help="end date inclusive", type=click_dt(format='%Y-%m-%d'))
|
|
||||||
def backfill_processing_time(start_date, end_date):
|
|
||||||
"""
|
|
||||||
Send historical processing time to Performance Platform.
|
|
||||||
"""
|
|
||||||
|
|
||||||
delta = end_date - start_date
|
|
||||||
|
|
||||||
print('Sending notification processing-time data for all days between {} and {}'.format(start_date, end_date))
|
|
||||||
|
|
||||||
for i in range(delta.days + 1):
|
|
||||||
# because the tz conversion funcs talk about midnight, and the midnight before last,
|
|
||||||
# we want to pretend we're running this from the next morning, so add one.
|
|
||||||
process_date = start_date + timedelta(days=i + 1)
|
|
||||||
|
|
||||||
process_start_date = get_midnight_for_day_before(process_date)
|
|
||||||
process_end_date = get_london_midnight_in_utc(process_date)
|
|
||||||
|
|
||||||
print('Sending notification processing-time for {} - {}'.format(
|
|
||||||
process_start_date.isoformat(),
|
|
||||||
process_end_date.isoformat()
|
|
||||||
))
|
|
||||||
send_processing_time_for_start_and_end(process_start_date, process_end_date, process_date)
|
|
||||||
|
|
||||||
|
|
||||||
@notify_command(name='populate-annual-billing')
|
@notify_command(name='populate-annual-billing')
|
||||||
@click.option('-y', '--year', required=True, type=int,
|
@click.option('-y', '--year', required=True, type=int,
|
||||||
help="""The year to populate the annual billing data for, i.e. 2019""")
|
help="""The year to populate the annual billing data for, i.e. 2019""")
|
||||||
@@ -951,78 +886,3 @@ def process_row_from_job(job_id, job_row_number):
|
|||||||
notification_id = process_row(row, template, job, job.service)
|
notification_id = process_row(row, template, job, job.service)
|
||||||
current_app.logger.info("Process row {} for job {} created notification_id: {}".format(
|
current_app.logger.info("Process row {} for job {} created notification_id: {}".format(
|
||||||
job_row_number, job_id, notification_id))
|
job_row_number, job_id, notification_id))
|
||||||
|
|
||||||
|
|
||||||
@notify_command(name='load-processing-time-data')
|
|
||||||
@click.option('-f', '--file_name', required=True, help='Text file contain json data for processing time')
|
|
||||||
def load_processing_time_data(file_name):
|
|
||||||
# This method loads the data from a text file that was downloaded from
|
|
||||||
# https://www.performance.service.gov.uk/data/govuk-notify/processing-time?flatten=true&duration=30&group_by=status&period=day&collect=count%3Asum&format=json ## noqa
|
|
||||||
# The data is formatted as a json
|
|
||||||
# {"data": [
|
|
||||||
# {
|
|
||||||
# "_count": 1.0,
|
|
||||||
# "_end_at": "2021-01-27T00:00:00+00:00",
|
|
||||||
# "_start_at": "2021-01-26T00:00:00+00:00",
|
|
||||||
# "count:sum": 4024207.0,
|
|
||||||
# "status": "messages-within-10-secs"
|
|
||||||
# },
|
|
||||||
# {
|
|
||||||
# "_count": 1.0,
|
|
||||||
# "_end_at": "2021-01-27T00:00:00+00:00",
|
|
||||||
# "_start_at": "2021-01-26T00:00:00+00:00",
|
|
||||||
# "count:sum": 4243204.0,
|
|
||||||
# "status": "messages-total"
|
|
||||||
# },
|
|
||||||
# ]}
|
|
||||||
#
|
|
||||||
# Using the fact_processing_time_dao.insert_update_processing_time means if this method is run more than once
|
|
||||||
# it will not throw an exception.
|
|
||||||
|
|
||||||
file = open(file_name)
|
|
||||||
|
|
||||||
file_contents = ""
|
|
||||||
for line in file:
|
|
||||||
file_contents += line
|
|
||||||
data = json.loads(file_contents)
|
|
||||||
normalised = []
|
|
||||||
|
|
||||||
class ProcesingTimeData:
|
|
||||||
bst_date = datetime(1990, 1, 1).date()
|
|
||||||
messages_total = 0
|
|
||||||
messages_within_10_secs = 0
|
|
||||||
|
|
||||||
def __eq__(self, obj):
|
|
||||||
return isinstance(obj, ProcesingTimeData) and obj.bst_date == self.bst_date
|
|
||||||
|
|
||||||
def set_bst_date(self, value):
|
|
||||||
self.bst_date = value
|
|
||||||
|
|
||||||
def set_m(self, status, value):
|
|
||||||
if status == 'messages-total':
|
|
||||||
self.messages_total = value
|
|
||||||
elif status == 'messages-within-10-secs':
|
|
||||||
self.messages_within_10_secs = value
|
|
||||||
|
|
||||||
for entry in data['data']:
|
|
||||||
bst_date = datetime.strptime(entry['_start_at'][0:10], "%Y-%m-%d").date()
|
|
||||||
status = entry['status']
|
|
||||||
value = entry['count:sum']
|
|
||||||
obj = ProcesingTimeData()
|
|
||||||
obj.set_bst_date(bst_date)
|
|
||||||
if obj in normalised:
|
|
||||||
normalised[normalised.index(obj)].set_m(status, value)
|
|
||||||
else:
|
|
||||||
d = ProcesingTimeData()
|
|
||||||
d.set_bst_date(bst_date)
|
|
||||||
d.set_m(status, value)
|
|
||||||
normalised.append(d)
|
|
||||||
for n in normalised:
|
|
||||||
print(n.bst_date, n.messages_total, n.messages_within_10_secs)
|
|
||||||
fact_processing_time = FactProcessingTime(bst_date=n.bst_date,
|
|
||||||
messages_total=n.messages_total,
|
|
||||||
messages_within_10_secs=n.messages_within_10_secs
|
|
||||||
)
|
|
||||||
insert_update_processing_time(fact_processing_time)
|
|
||||||
|
|
||||||
print("Done loading processing time data.")
|
|
||||||
|
|||||||
@@ -109,10 +109,6 @@ class Config(object):
|
|||||||
EXPIRE_CACHE_TEN_MINUTES = 600
|
EXPIRE_CACHE_TEN_MINUTES = 600
|
||||||
EXPIRE_CACHE_EIGHT_DAYS = 8 * 24 * 60 * 60
|
EXPIRE_CACHE_EIGHT_DAYS = 8 * 24 * 60 * 60
|
||||||
|
|
||||||
# Performance platform
|
|
||||||
PERFORMANCE_PLATFORM_ENABLED = False
|
|
||||||
PERFORMANCE_PLATFORM_URL = 'https://www.performance.service.gov.uk/data/govuk-notify/'
|
|
||||||
|
|
||||||
# Zendesk
|
# Zendesk
|
||||||
ZENDESK_API_KEY = os.environ.get('ZENDESK_API_KEY')
|
ZENDESK_API_KEY = os.environ.get('ZENDESK_API_KEY')
|
||||||
|
|
||||||
@@ -273,11 +269,6 @@ class Config(object):
|
|||||||
'schedule': crontab(hour=1, minute=40),
|
'schedule': crontab(hour=1, minute=40),
|
||||||
'options': {'queue': QueueNames.PERIODIC}
|
'options': {'queue': QueueNames.PERIODIC}
|
||||||
},
|
},
|
||||||
'send-daily-performance-platform-stats': {
|
|
||||||
'task': 'send-daily-performance-platform-stats',
|
|
||||||
'schedule': crontab(hour=2, minute=0),
|
|
||||||
'options': {'queue': QueueNames.PERIODIC}
|
|
||||||
},
|
|
||||||
'save-daily-notification-processing-time': {
|
'save-daily-notification-processing-time': {
|
||||||
'task': 'save-daily-notification-processing-time',
|
'task': 'save-daily-notification-processing-time',
|
||||||
'schedule': crontab(hour=2, minute=0),
|
'schedule': crontab(hour=2, minute=0),
|
||||||
@@ -366,10 +357,6 @@ class Config(object):
|
|||||||
|
|
||||||
HIGH_VOLUME_SERVICE = json.loads(os.environ.get('HIGH_VOLUME_SERVICE', '[]'))
|
HIGH_VOLUME_SERVICE = json.loads(os.environ.get('HIGH_VOLUME_SERVICE', '[]'))
|
||||||
|
|
||||||
# Format is as follows:
|
|
||||||
# {"dataset_1": "token_1", ...}
|
|
||||||
PERFORMANCE_PLATFORM_ENDPOINTS = json.loads(os.environ.get('PERFORMANCE_PLATFORM_ENDPOINTS', '{}'))
|
|
||||||
|
|
||||||
TEMPLATE_PREVIEW_API_HOST = os.environ.get('TEMPLATE_PREVIEW_API_HOST', 'http://localhost:6013')
|
TEMPLATE_PREVIEW_API_HOST = os.environ.get('TEMPLATE_PREVIEW_API_HOST', 'http://localhost:6013')
|
||||||
TEMPLATE_PREVIEW_API_KEY = os.environ.get('TEMPLATE_PREVIEW_API_KEY', 'my-secret-key')
|
TEMPLATE_PREVIEW_API_KEY = os.environ.get('TEMPLATE_PREVIEW_API_KEY', 'my-secret-key')
|
||||||
|
|
||||||
@@ -537,7 +524,6 @@ class Live(Config):
|
|||||||
TRANSIENT_UPLOADED_LETTERS = 'production-transient-uploaded-letters'
|
TRANSIENT_UPLOADED_LETTERS = 'production-transient-uploaded-letters'
|
||||||
LETTER_SANITISE_BUCKET_NAME = 'production-letters-sanitise'
|
LETTER_SANITISE_BUCKET_NAME = 'production-letters-sanitise'
|
||||||
FROM_NUMBER = 'GOVUK'
|
FROM_NUMBER = 'GOVUK'
|
||||||
PERFORMANCE_PLATFORM_ENABLED = True
|
|
||||||
API_RATE_LIMIT_ENABLED = True
|
API_RATE_LIMIT_ENABLED = True
|
||||||
CHECK_PROXY_HEADER = True
|
CHECK_PROXY_HEADER = True
|
||||||
SES_STUB_URL = None
|
SES_STUB_URL = None
|
||||||
|
|||||||
@@ -430,18 +430,6 @@ def fetch_monthly_template_usage_for_service(start_date, end_date, service_id):
|
|||||||
return query.all()
|
return query.all()
|
||||||
|
|
||||||
|
|
||||||
def get_total_sent_notifications_for_day_and_type(day, notification_type):
|
|
||||||
result = db.session.query(
|
|
||||||
func.sum(FactNotificationStatus.notification_count).label('count')
|
|
||||||
).filter(
|
|
||||||
FactNotificationStatus.notification_type == notification_type,
|
|
||||||
FactNotificationStatus.key_type != KEY_TYPE_TEST,
|
|
||||||
FactNotificationStatus.bst_date == day,
|
|
||||||
).scalar()
|
|
||||||
|
|
||||||
return result or 0
|
|
||||||
|
|
||||||
|
|
||||||
def get_total_notifications_for_date_range(start_date, end_date):
|
def get_total_notifications_for_date_range(start_date, end_date):
|
||||||
query = db.session.query(
|
query = db.session.query(
|
||||||
FactNotificationStatus.bst_date.cast(db.Text).label("bst_date"),
|
FactNotificationStatus.bst_date.cast(db.Text).label("bst_date"),
|
||||||
|
|||||||
@@ -684,8 +684,11 @@ def dao_get_notifications_by_references(references):
|
|||||||
).all()
|
).all()
|
||||||
|
|
||||||
|
|
||||||
def dao_get_total_notifications_sent_per_day_for_performance_platform(start_date, end_date):
|
def dao_get_notifications_processing_time_stats(start_date, end_date):
|
||||||
"""
|
"""
|
||||||
|
For a given time range, returns the number of notifications sent and the number of
|
||||||
|
those notifications that we processed within 10 seconds
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
count(notifications),
|
count(notifications),
|
||||||
coalesce(sum(CASE WHEN sent_at - created_at <= interval '10 seconds' THEN 1 ELSE 0 END), 0)
|
coalesce(sum(CASE WHEN sent_at - created_at <= interval '10 seconds' THEN 1 ELSE 0 END), 0)
|
||||||
|
|||||||
@@ -118,9 +118,6 @@ applications:
|
|||||||
|
|
||||||
HIGH_VOLUME_SERVICE: '{{ HIGH_VOLUME_SERVICE | tojson }}'
|
HIGH_VOLUME_SERVICE: '{{ HIGH_VOLUME_SERVICE | tojson }}'
|
||||||
|
|
||||||
|
|
||||||
PERFORMANCE_PLATFORM_ENDPOINTS: '{{ PERFORMANCE_PLATFORM_ENDPOINTS | tojson }}'
|
|
||||||
|
|
||||||
DOCUMENT_DOWNLOAD_API_HOST: '{{ DOCUMENT_DOWNLOAD_API_HOST }}'
|
DOCUMENT_DOWNLOAD_API_HOST: '{{ DOCUMENT_DOWNLOAD_API_HOST }}'
|
||||||
DOCUMENT_DOWNLOAD_API_KEY: '{{ DOCUMENT_DOWNLOAD_API_KEY }}'
|
DOCUMENT_DOWNLOAD_API_KEY: '{{ DOCUMENT_DOWNLOAD_API_KEY }}'
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from unittest.mock import PropertyMock, call, patch
|
from unittest.mock import call
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import pytz
|
import pytz
|
||||||
@@ -20,21 +20,15 @@ from app.celery.nightly_tasks import (
|
|||||||
remove_sms_email_csv_files,
|
remove_sms_email_csv_files,
|
||||||
s3,
|
s3,
|
||||||
save_daily_notification_processing_time,
|
save_daily_notification_processing_time,
|
||||||
send_daily_performance_platform_stats,
|
|
||||||
send_total_sent_notifications_to_performance_platform,
|
|
||||||
timeout_notifications,
|
timeout_notifications,
|
||||||
)
|
)
|
||||||
from app.celery.service_callback_tasks import (
|
from app.celery.service_callback_tasks import (
|
||||||
create_delivery_status_callback_data,
|
create_delivery_status_callback_data,
|
||||||
)
|
)
|
||||||
from app.clients.performance_platform.performance_platform_client import (
|
|
||||||
PerformancePlatformClient,
|
|
||||||
)
|
|
||||||
from app.config import QueueNames
|
from app.config import QueueNames
|
||||||
from app.exceptions import NotificationTechnicalFailureException
|
from app.exceptions import NotificationTechnicalFailureException
|
||||||
from app.models import EMAIL_TYPE, LETTER_TYPE, SMS_TYPE, FactProcessingTime
|
from app.models import EMAIL_TYPE, LETTER_TYPE, SMS_TYPE, FactProcessingTime
|
||||||
from tests.app.db import (
|
from tests.app.db import (
|
||||||
create_ft_notification_status,
|
|
||||||
create_job,
|
create_job,
|
||||||
create_notification,
|
create_notification,
|
||||||
create_service,
|
create_service,
|
||||||
@@ -232,55 +226,6 @@ def test_timeout_notifications_sends_status_update_to_service(client, sample_tem
|
|||||||
mocked.assert_called_once_with([str(notification.id), encrypted_data], queue=QueueNames.CALLBACKS)
|
mocked.assert_called_once_with([str(notification.id), encrypted_data], queue=QueueNames.CALLBACKS)
|
||||||
|
|
||||||
|
|
||||||
def test_send_daily_performance_stats_calls_does_not_send_if_inactive(client, mocker):
|
|
||||||
send_mock = mocker.patch(
|
|
||||||
'app.celery.nightly_tasks.total_sent_notifications.send_total_notifications_sent_for_day_stats') # noqa
|
|
||||||
|
|
||||||
with patch.object(
|
|
||||||
PerformancePlatformClient,
|
|
||||||
'active',
|
|
||||||
new_callable=PropertyMock
|
|
||||||
) as mock_active:
|
|
||||||
mock_active.return_value = False
|
|
||||||
send_daily_performance_platform_stats()
|
|
||||||
|
|
||||||
assert send_mock.call_count == 0
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time("2016-06-11 02:00:00")
|
|
||||||
def test_send_total_sent_notifications_to_performance_platform_calls_with_correct_totals(
|
|
||||||
notify_db_session,
|
|
||||||
sample_template,
|
|
||||||
sample_email_template,
|
|
||||||
mocker
|
|
||||||
):
|
|
||||||
perf_mock = mocker.patch(
|
|
||||||
'app.celery.nightly_tasks.total_sent_notifications.send_total_notifications_sent_for_day_stats') # noqa
|
|
||||||
|
|
||||||
today = date(2016, 6, 11)
|
|
||||||
create_ft_notification_status(bst_date=today, template=sample_template)
|
|
||||||
create_ft_notification_status(bst_date=today, template=sample_email_template)
|
|
||||||
|
|
||||||
# Create some notifications for the day before
|
|
||||||
yesterday = date(2016, 6, 10)
|
|
||||||
create_ft_notification_status(bst_date=yesterday, template=sample_template, count=2)
|
|
||||||
create_ft_notification_status(bst_date=yesterday, template=sample_email_template, count=3)
|
|
||||||
|
|
||||||
with patch.object(
|
|
||||||
PerformancePlatformClient,
|
|
||||||
'active',
|
|
||||||
new_callable=PropertyMock
|
|
||||||
) as mock_active:
|
|
||||||
mock_active.return_value = True
|
|
||||||
send_total_sent_notifications_to_performance_platform(yesterday)
|
|
||||||
|
|
||||||
perf_mock.assert_has_calls([
|
|
||||||
call(datetime(2016, 6, 9, 23, 0), 'sms', 2),
|
|
||||||
call(datetime(2016, 6, 9, 23, 0), 'email', 3),
|
|
||||||
call(datetime(2016, 6, 9, 23, 0), 'letter', 0)
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
def test_should_call_delete_inbound_sms(notify_api, mocker):
|
def test_should_call_delete_inbound_sms(notify_api, mocker):
|
||||||
mocker.patch('app.celery.nightly_tasks.delete_inbound_sms_older_than_retention')
|
mocker.patch('app.celery.nightly_tasks.delete_inbound_sms_older_than_retention')
|
||||||
delete_inbound_sms()
|
delete_inbound_sms()
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from app.commands import (
|
|
||||||
backfill_performance_platform_totals,
|
|
||||||
backfill_processing_time,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_backfill_processing_time_works_for_correct_dates(mocker, notify_api):
|
|
||||||
send_mock = mocker.patch('app.commands.send_processing_time_for_start_and_end')
|
|
||||||
|
|
||||||
# backfill_processing_time is a click.Command object - if you try invoking the callback on its own, it
|
|
||||||
# throws a `RuntimeError: There is no active click context.` - so get at the original function using __wrapped__
|
|
||||||
backfill_processing_time.callback.__wrapped__(datetime(2017, 8, 1), datetime(2017, 8, 3))
|
|
||||||
|
|
||||||
assert send_mock.call_count == 3
|
|
||||||
send_mock.assert_any_call(datetime(2017, 7, 31, 23, 0), datetime(2017, 8, 1, 23, 0), datetime(2017, 8, 2, 0, 0))
|
|
||||||
send_mock.assert_any_call(datetime(2017, 8, 1, 23, 0), datetime(2017, 8, 2, 23, 0), datetime(2017, 8, 3, 0, 0))
|
|
||||||
send_mock.assert_any_call(datetime(2017, 8, 2, 23, 0), datetime(2017, 8, 3, 23, 0), datetime(2017, 8, 4, 0, 0))
|
|
||||||
|
|
||||||
|
|
||||||
def test_backfill_totals_works_for_correct_dates(mocker, notify_api):
|
|
||||||
send_mock = mocker.patch('app.commands.send_total_sent_notifications_to_performance_platform')
|
|
||||||
|
|
||||||
# backfill_processing_time is a click.Command object - if you try invoking the callback on its own, it
|
|
||||||
# throws a `RuntimeError: There is no active click context.` - so get at the original function using __wrapped__
|
|
||||||
backfill_performance_platform_totals.callback.__wrapped__(datetime(2017, 8, 1), datetime(2017, 8, 3))
|
|
||||||
|
|
||||||
assert send_mock.call_count == 3
|
|
||||||
send_mock.assert_any_call(datetime(2017, 8, 1))
|
|
||||||
send_mock.assert_any_call(datetime(2017, 8, 2))
|
|
||||||
send_mock.assert_any_call(datetime(2017, 8, 3))
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
from datetime import date, datetime, timedelta
|
|
||||||
|
|
||||||
from freezegun import freeze_time
|
|
||||||
|
|
||||||
from app.dao.notifications_dao import (
|
|
||||||
dao_get_total_notifications_sent_per_day_for_performance_platform,
|
|
||||||
)
|
|
||||||
from app.models import KEY_TYPE_NORMAL, KEY_TYPE_TEAM, KEY_TYPE_TEST
|
|
||||||
from tests.app.db import create_notification
|
|
||||||
|
|
||||||
BEGINNING_OF_DAY = date(2016, 10, 18)
|
|
||||||
END_OF_DAY = date(2016, 10, 19)
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_total_notifications_filters_on_date_within_date_range(sample_template):
|
|
||||||
create_notification(sample_template, created_at=datetime(2016, 10, 17, 23, 59, 59))
|
|
||||||
create_notification(sample_template, created_at=BEGINNING_OF_DAY)
|
|
||||||
create_notification(sample_template, created_at=datetime(2016, 10, 18, 23, 59, 59))
|
|
||||||
create_notification(sample_template, created_at=END_OF_DAY)
|
|
||||||
|
|
||||||
result = dao_get_total_notifications_sent_per_day_for_performance_platform(BEGINNING_OF_DAY, END_OF_DAY)
|
|
||||||
|
|
||||||
assert result.messages_total == 2
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2016-10-18T10:00')
|
|
||||||
def test_get_total_notifications_only_counts_api_notifications(sample_template, sample_job, sample_api_key):
|
|
||||||
create_notification(sample_template, one_off=True)
|
|
||||||
create_notification(sample_template, one_off=True)
|
|
||||||
create_notification(sample_template, job=sample_job)
|
|
||||||
create_notification(sample_template, job=sample_job)
|
|
||||||
create_notification(sample_template, api_key=sample_api_key)
|
|
||||||
|
|
||||||
result = dao_get_total_notifications_sent_per_day_for_performance_platform(BEGINNING_OF_DAY, END_OF_DAY)
|
|
||||||
|
|
||||||
assert result.messages_total == 1
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2016-10-18T10:00')
|
|
||||||
def test_get_total_notifications_ignores_test_keys(sample_template):
|
|
||||||
# Creating multiple templates with normal and team keys but only 1 template
|
|
||||||
# with a test key to test that the count ignores letters
|
|
||||||
create_notification(sample_template, key_type=KEY_TYPE_NORMAL)
|
|
||||||
create_notification(sample_template, key_type=KEY_TYPE_NORMAL)
|
|
||||||
create_notification(sample_template, key_type=KEY_TYPE_TEAM)
|
|
||||||
create_notification(sample_template, key_type=KEY_TYPE_TEAM)
|
|
||||||
create_notification(sample_template, key_type=KEY_TYPE_TEST)
|
|
||||||
|
|
||||||
result = dao_get_total_notifications_sent_per_day_for_performance_platform(BEGINNING_OF_DAY, END_OF_DAY)
|
|
||||||
|
|
||||||
assert result.messages_total == 4
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2016-10-18T10:00')
|
|
||||||
def test_get_total_notifications_ignores_letters(
|
|
||||||
sample_template,
|
|
||||||
sample_email_template,
|
|
||||||
sample_letter_template
|
|
||||||
):
|
|
||||||
# Creating multiple sms and email templates but only 1 letter template to
|
|
||||||
# test that the count ignores letters
|
|
||||||
create_notification(sample_template)
|
|
||||||
create_notification(sample_template)
|
|
||||||
create_notification(sample_email_template)
|
|
||||||
create_notification(sample_email_template)
|
|
||||||
create_notification(sample_letter_template)
|
|
||||||
|
|
||||||
result = dao_get_total_notifications_sent_per_day_for_performance_platform(BEGINNING_OF_DAY, END_OF_DAY)
|
|
||||||
|
|
||||||
assert result.messages_total == 4
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2016-10-18T10:00')
|
|
||||||
def test_get_total_notifications_counts_messages_within_10_seconds(sample_template):
|
|
||||||
created_at = datetime.utcnow()
|
|
||||||
|
|
||||||
create_notification(sample_template, sent_at=created_at + timedelta(seconds=5))
|
|
||||||
create_notification(sample_template, sent_at=created_at + timedelta(seconds=10))
|
|
||||||
create_notification(sample_template, sent_at=created_at + timedelta(seconds=15))
|
|
||||||
|
|
||||||
result = dao_get_total_notifications_sent_per_day_for_performance_platform(BEGINNING_OF_DAY, END_OF_DAY)
|
|
||||||
|
|
||||||
assert result.messages_total == 3
|
|
||||||
assert result.messages_within_10_secs == 2
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2016-10-18T10:00')
|
|
||||||
def test_get_total_notifications_counts_messages_that_have_not_sent(sample_template):
|
|
||||||
create_notification(sample_template, status='created', sent_at=None)
|
|
||||||
|
|
||||||
result = dao_get_total_notifications_sent_per_day_for_performance_platform(BEGINNING_OF_DAY, END_OF_DAY)
|
|
||||||
|
|
||||||
assert result.messages_total == 1
|
|
||||||
assert result.messages_within_10_secs == 0
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2016-10-18T10:00')
|
|
||||||
def test_get_total_notifications_returns_zero_if_no_data(notify_db_session):
|
|
||||||
result = dao_get_total_notifications_sent_per_day_for_performance_platform(BEGINNING_OF_DAY, END_OF_DAY)
|
|
||||||
|
|
||||||
assert result.messages_total == 0
|
|
||||||
assert result.messages_within_10_secs == 0
|
|
||||||
@@ -16,7 +16,6 @@ from app.dao.fact_notification_status_dao import (
|
|||||||
fetch_notification_statuses_for_job,
|
fetch_notification_statuses_for_job,
|
||||||
fetch_stats_for_all_services_by_date_range,
|
fetch_stats_for_all_services_by_date_range,
|
||||||
get_total_notifications_for_date_range,
|
get_total_notifications_for_date_range,
|
||||||
get_total_sent_notifications_for_day_and_type,
|
|
||||||
update_fact_notification_status,
|
update_fact_notification_status,
|
||||||
)
|
)
|
||||||
from app.models import (
|
from app.models import (
|
||||||
@@ -601,51 +600,6 @@ def test_fetch_monthly_template_usage_for_service_does_not_include_test_notifica
|
|||||||
assert len(results) == 0
|
assert len(results) == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("notification_type, count",
|
|
||||||
[("sms", 3),
|
|
||||||
("email", 5),
|
|
||||||
("letter", 7)])
|
|
||||||
def test_get_total_sent_notifications_for_day_and_type_returns_right_notification_type(
|
|
||||||
notification_type, count, sample_template, sample_email_template, sample_letter_template
|
|
||||||
):
|
|
||||||
create_ft_notification_status(bst_date="2019-03-27", service=sample_template.service, template=sample_template,
|
|
||||||
count=3)
|
|
||||||
create_ft_notification_status(bst_date="2019-03-27", service=sample_email_template.service,
|
|
||||||
template=sample_email_template, count=5)
|
|
||||||
create_ft_notification_status(bst_date="2019-03-27", service=sample_letter_template.service,
|
|
||||||
template=sample_letter_template, count=7)
|
|
||||||
|
|
||||||
result = get_total_sent_notifications_for_day_and_type(day='2019-03-27', notification_type=notification_type)
|
|
||||||
|
|
||||||
assert result == count
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("day",
|
|
||||||
["2019-01-27", "2019-04-02"])
|
|
||||||
def test_get_total_sent_notifications_for_day_and_type_returns_total_for_right_day(
|
|
||||||
day, sample_template
|
|
||||||
):
|
|
||||||
date = datetime.strptime(day, "%Y-%m-%d")
|
|
||||||
create_ft_notification_status(bst_date=date - timedelta(days=1), notification_type=sample_template.template_type,
|
|
||||||
service=sample_template.service, template=sample_template, count=1)
|
|
||||||
create_ft_notification_status(bst_date=date, notification_type=sample_template.template_type,
|
|
||||||
service=sample_template.service, template=sample_template, count=2)
|
|
||||||
create_ft_notification_status(bst_date=date + timedelta(days=1), notification_type=sample_template.template_type,
|
|
||||||
service=sample_template.service, template=sample_template, count=3)
|
|
||||||
|
|
||||||
total = get_total_sent_notifications_for_day_and_type(day, sample_template.template_type)
|
|
||||||
|
|
||||||
assert total == 2
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_total_sent_notifications_for_day_and_type_returns_zero_when_no_counts(
|
|
||||||
notify_db_session
|
|
||||||
):
|
|
||||||
total = get_total_sent_notifications_for_day_and_type("2019-03-27", "sms")
|
|
||||||
|
|
||||||
assert total == 0
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2019-05-10 14:00')
|
@freeze_time('2019-05-10 14:00')
|
||||||
def test_fetch_monthly_notification_statuses_per_service(notify_db_session):
|
def test_fetch_monthly_notification_statuses_per_service(notify_db_session):
|
||||||
service_one = create_service(service_name='service one', service_id=UUID('e4e34c4e-73c1-4802-811c-3dd273f21da4'))
|
service_one = create_service(service_name='service one', service_id=UUID('e4e34c4e-73c1-4802-811c-3dd273f21da4'))
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
from datetime import date, datetime, timedelta
|
|
||||||
|
|
||||||
from freezegun import freeze_time
|
|
||||||
|
|
||||||
from app.performance_platform.processing_time import (
|
|
||||||
send_processing_time_data,
|
|
||||||
send_processing_time_to_performance_platform,
|
|
||||||
)
|
|
||||||
from tests.app.db import create_notification
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2016-10-18T02:00')
|
|
||||||
def test_send_processing_time_to_performance_platform_generates_correct_calls(mocker, sample_template):
|
|
||||||
send_mock = mocker.patch('app.performance_platform.processing_time.send_processing_time_data')
|
|
||||||
|
|
||||||
created_at = datetime.utcnow() - timedelta(days=1)
|
|
||||||
|
|
||||||
create_notification(sample_template, created_at=created_at, sent_at=created_at + timedelta(seconds=5))
|
|
||||||
create_notification(sample_template, created_at=created_at, sent_at=created_at + timedelta(seconds=15))
|
|
||||||
create_notification(sample_template, created_at=datetime.utcnow() - timedelta(days=2))
|
|
||||||
|
|
||||||
send_processing_time_to_performance_platform(date(2016, 10, 17))
|
|
||||||
|
|
||||||
send_mock.assert_any_call(datetime(2016, 10, 16, 23, 0), 'messages-total', 2)
|
|
||||||
send_mock.assert_any_call(datetime(2016, 10, 16, 23, 0), 'messages-within-10-secs', 1)
|
|
||||||
|
|
||||||
|
|
||||||
def test_send_processing_time_to_performance_platform_creates_correct_call_to_perf_platform(mocker):
|
|
||||||
send_stats = mocker.patch('app.performance_platform.total_sent_notifications.performance_platform_client.send_stats_to_performance_platform') # noqa
|
|
||||||
|
|
||||||
send_processing_time_data(
|
|
||||||
start_time=datetime(2016, 10, 15, 23, 0, 0),
|
|
||||||
status='foo',
|
|
||||||
count=142
|
|
||||||
)
|
|
||||||
|
|
||||||
assert send_stats.call_count == 1
|
|
||||||
|
|
||||||
request_args = send_stats.call_args[0][0]
|
|
||||||
assert request_args['dataType'] == 'processing-time'
|
|
||||||
assert request_args['service'] == 'govuk-notify'
|
|
||||||
assert request_args['period'] == 'day'
|
|
||||||
assert request_args['status'] == 'foo'
|
|
||||||
assert request_args['_timestamp'] == '2016-10-16T00:00:00'
|
|
||||||
assert request_args['count'] == 142
|
|
||||||
expected_base64_id = 'MjAxNi0xMC0xNlQwMDowMDowMGdvdnVrLW5vdGlmeWZvb3Byb2Nlc3NpbmctdGltZWRheQ=='
|
|
||||||
assert request_args['_id'] == expected_base64_id
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
from datetime import date, datetime
|
|
||||||
|
|
||||||
from freezegun import freeze_time
|
|
||||||
|
|
||||||
from app.performance_platform.total_sent_notifications import (
|
|
||||||
get_total_sent_notifications_for_day,
|
|
||||||
send_total_notifications_sent_for_day_stats,
|
|
||||||
)
|
|
||||||
from tests.app.db import create_ft_notification_status, create_template
|
|
||||||
|
|
||||||
|
|
||||||
def test_send_total_notifications_sent_for_day_stats_stats_creates_correct_call(mocker, client):
|
|
||||||
send_stats = mocker.patch('app.performance_platform.total_sent_notifications.performance_platform_client.send_stats_to_performance_platform') # noqa
|
|
||||||
|
|
||||||
send_total_notifications_sent_for_day_stats(
|
|
||||||
start_time=datetime(2016, 10, 15, 23, 0, 0),
|
|
||||||
notification_type='sms',
|
|
||||||
count=142
|
|
||||||
)
|
|
||||||
|
|
||||||
assert send_stats.call_count == 1
|
|
||||||
|
|
||||||
request_args = send_stats.call_args[0][0]
|
|
||||||
assert request_args['dataType'] == 'notifications'
|
|
||||||
assert request_args['service'] == 'govuk-notify'
|
|
||||||
assert request_args['period'] == 'day'
|
|
||||||
assert request_args['channel'] == 'sms'
|
|
||||||
assert request_args['_timestamp'] == '2016-10-16T00:00:00'
|
|
||||||
assert request_args['count'] == 142
|
|
||||||
expected_base64_id = 'MjAxNi0xMC0xNlQwMDowMDowMGdvdnVrLW5vdGlmeXNtc25vdGlmaWNhdGlvbnNkYXk='
|
|
||||||
assert request_args['_id'] == expected_base64_id
|
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2018-06-10 01:00')
|
|
||||||
def test_get_total_sent_notifications_yesterday_returns_expected_totals_dict(sample_service):
|
|
||||||
sms = create_template(sample_service, template_type='sms')
|
|
||||||
email = create_template(sample_service, template_type='email')
|
|
||||||
letter = create_template(sample_service, template_type='letter')
|
|
||||||
|
|
||||||
today = date(2018, 6, 10)
|
|
||||||
yesterday = date(2018, 6, 9)
|
|
||||||
|
|
||||||
# todays is excluded
|
|
||||||
create_ft_notification_status(bst_date=today, template=sms)
|
|
||||||
create_ft_notification_status(bst_date=today, template=email)
|
|
||||||
create_ft_notification_status(bst_date=today, template=letter)
|
|
||||||
|
|
||||||
# yesterdays is included
|
|
||||||
create_ft_notification_status(bst_date=yesterday, template=sms, count=2)
|
|
||||||
create_ft_notification_status(bst_date=yesterday, template=email, count=3)
|
|
||||||
create_ft_notification_status(bst_date=yesterday, template=letter, count=1)
|
|
||||||
|
|
||||||
total_count_dict = get_total_sent_notifications_for_day(yesterday)
|
|
||||||
|
|
||||||
assert total_count_dict == {
|
|
||||||
"email": 3,
|
|
||||||
"sms": 2,
|
|
||||||
"letter": 1
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user