def test_check_service_message_limit_in_cache_over_message_limit_fails( notify_db_session, key_type, mocker): with freeze_time("2016-01-01 12:00:00.000000"): mocker.patch('app.redis_store.get', return_value=5) mocker.patch('app.notifications.validators.redis_store.set') mocker.patch('app.notifications.validators.services_dao') service = create_service(restricted=True, message_limit=4) with pytest.raises(TooManyRequestsError) as e: check_service_over_daily_message_limit(key_type, service) assert e.value.status_code == 429 assert e.value.message == 'Exceeded send limits (4) for today' assert e.value.fields == [] app.notifications.validators.redis_store.set.assert_not_called() assert not app.notifications.validators.services_dao.mock_calls
def test_check_service_message_limit_skip_statsd_over_message_no_limit_fails( app_statsd, notify_db, notify_db_session, mocker): # Given mocker.patch('app.redis_store.get', return_value=0) mocker.patch('app.notifications.validators.redis_store.set') # When service = create_service(notify_db, notify_db_session, restricted=True, limit=4) check_service_over_daily_message_limit("normal", service) # Then app_statsd.statsd_client.incr.assert_not_called()
def test_should_set_cache_value_as_value_from_database_if_cache_not_set( key_type, notify_db, notify_db_session, sample_service, mocker ): with freeze_time("2016-01-01 12:00:00.000000"): for x in range(5): create_notification(notify_db, notify_db_session, service=sample_service) mocker.patch('app.notifications.validators.redis_store.get', return_value=None) mocker.patch('app.notifications.validators.redis_store.set') check_service_over_daily_message_limit(key_type, sample_service) app.notifications.validators.redis_store.set.assert_called_with( str(sample_service.id) + "-2016-01-01-count", 5, ex=3600 )
def test_check_service_message_limit_over_message_limit_fails(key_type, notify_db, notify_db_session, mocker): with freeze_time("2016-01-01 12:00:00.000000"): mocker.patch('app.redis_store.get', return_value=None) mocker.patch('app.notifications.validators.redis_store.set') service = create_service(notify_db, notify_db_session, restricted=True, limit=4) for x in range(5): create_notification(notify_db, notify_db_session, service=service) with pytest.raises(TooManyRequestsError) as e: check_service_over_daily_message_limit(key_type, service) assert e.value.status_code == 429 assert e.value.message == 'Exceeded send limits (4) for today' assert e.value.fields == [] app.notifications.validators.redis_store.set.assert_called_with( str(service.id) + "-2016-01-01-count", 5, ex=3600 )
def test_check_service_message_limit_sends_statsd_over_message_limit_fails( app_statsd, notify_db, notify_db_session, mocker): # Given mocker.patch('app.redis_store.get', return_value=5) mocker.patch('app.notifications.validators.redis_store.set') # When service = create_service(notify_db, notify_db_session, restricted=True, limit=4) with pytest.raises(TooManyRequestsError): check_service_over_daily_message_limit("normal", service) # Then app_statsd.statsd_client.incr.assert_called_once_with( "validators.rate_limit.service_daily")
def test_should_set_cache_value_as_value_from_database_if_cache_not_set( key_type, sample_template, sample_service, mocker ): with freeze_time("2016-01-01 12:00:00.000000"): current_app.config['API_MESSAGE_LIMIT_ENABLED'] = True for x in range(5): create_notification(sample_template) mocker.patch('app.notifications.validators.redis_store.get', return_value=None) mocker.patch('app.notifications.validators.redis_store.set') check_service_over_daily_message_limit(key_type, sample_service) app.notifications.validators.redis_store.set.assert_called_with( str(sample_service.id) + "-2016-01-01-count", 5, ex=3600 )
def test_check_service_message_limit_in_cache_under_message_limit_passes( key_type, sample_service, mocker): mocker.patch('app.notifications.validators.redis_store.get', side_effect=[ None, # The serialised service 1, # The rolling count ]) mocker.patch('app.notifications.validators.redis_store.set') mocker.patch('app.notifications.validators.services_dao') serialised_service = SerialisedService.from_id(sample_service.id) check_service_over_daily_message_limit(key_type, serialised_service) app.notifications.validators.redis_store.set.assert_called_once_with( f'service-{serialised_service.id}', ANY, ex=ANY, ) assert not app.notifications.validators.services_dao.mock_calls
def test_check_service_message_limit_sends_statsd_over_message_limit_fails( app_statsd, notify_db, notify_db_session, mocker, is_trial_service, expected_counter, ): mocker.patch("app.redis_store.get", return_value=5) mocker.patch("app.notifications.validators.redis_store.set") service = create_service(notify_db, notify_db_session, restricted=is_trial_service, limit=4) with pytest.raises(TooManyRequestsError): check_service_over_daily_message_limit("normal", service) app_statsd.statsd_client.incr.assert_called_once_with(expected_counter)
def test_check_service_message_limit_over_message_limit_fails( key_type, notify_db, notify_db_session, mocker): with freeze_time("2016-01-01 12:00:00.000000"): redis_get = mocker.patch("app.redis_store.get", side_effect=["5", True, None]) redis_set = mocker.patch("app.redis_store.set") send_notification = mocker.patch( "app.notifications.validators.send_notification_to_service_users") service = create_service(notify_db, notify_db_session, restricted=True, limit=4) for x in range(5): create_notification(notify_db, notify_db_session, service=service) with pytest.raises(TooManyRequestsError) as e: check_service_over_daily_message_limit(key_type, service) assert e.value.status_code == 429 assert e.value.message == "Exceeded send limits (4) for today" assert e.value.fields == [] assert redis_get.call_args_list == [ call(f"{service.id}-2016-01-01-count"), call(f"nearing-{service.id}-2016-01-01-count"), call(f"over-{service.id}-2016-01-01-count"), ] assert redis_set.call_args_list == [ call(f"over-{service.id}-2016-01-01-count", "2016-01-01T12:00:00", ex=86400) ] send_notification.assert_called_once_with( service_id=service.id, template_id=current_app.config["REACHED_DAILY_LIMIT_TEMPLATE_ID"], personalisation={ "service_name": service.name, "contact_url": f"{current_app.config['ADMIN_BASE_URL']}/contact", "message_limit_en": "4", "message_limit_fr": "4", }, include_user_fields=["name"], )
def test_check_service_message_limit_over_message_limit_fails(key_type, sample_service, mocker): with freeze_time("2016-01-01 12:00:00.000000"): current_app.config['API_MESSAGE_LIMIT_ENABLED'] = True mocker.patch('app.redis_store.get', return_value=None) mocker.patch('app.notifications.validators.redis_store.set') sample_service.restricted = True sample_service.message_limit = 4 template = create_template(sample_service) for x in range(5): create_notification(template) with pytest.raises(TooManyRequestsError) as e: check_service_over_daily_message_limit(key_type, sample_service) assert e.value.status_code == 429 assert e.value.message == 'Exceeded send limits (4) for today' assert e.value.fields == [] app.notifications.validators.redis_store.set.assert_called_with( str(sample_service.id) + "-2016-01-01-count", 5, ex=3600 )
def test_check_service_message_limit_records_nearing_daily_limit( notify_db, notify_db_session, mocker): with freeze_time("2016-01-01 12:00:00.000000"): redis_get = mocker.patch("app.redis_store.get", side_effect=[4, None]) redis_set = mocker.patch("app.redis_store.set") send_notification = mocker.patch( "app.notifications.validators.send_notification_to_service_users") service = create_service(notify_db, notify_db_session, restricted=True, limit=5) for x in range(4): create_notification(notify_db, notify_db_session, service=service) check_service_over_daily_message_limit("normal", service) assert redis_get.call_args_list == [ call(f"{service.id}-2016-01-01-count"), call(f"nearing-{service.id}-2016-01-01-count"), ] assert redis_set.call_args_list == [ call( f"nearing-{service.id}-2016-01-01-count", "2016-01-01T12:00:00", ex=86400, ), ] send_notification.assert_called_once_with( service_id=service.id, template_id=current_app.config["NEAR_DAILY_LIMIT_TEMPLATE_ID"], personalisation={ "service_name": service.name, "contact_url": f"{current_app.config['ADMIN_BASE_URL']}/contact", "message_limit_en": "5", "message_limit_fr": "5", }, include_user_fields=["name"], )
def send_one_off_notification(service_id, post_data): service = dao_fetch_service_by_id(service_id) template = dao_get_template_by_id_and_service_id( template_id=post_data['template_id'], service_id=service_id) personalisation = post_data.get('personalisation', None) validate_template(template.id, personalisation, service, template.template_type) check_service_over_daily_message_limit(KEY_TYPE_NORMAL, service) validate_and_format_recipient( send_to=post_data['to'], key_type=KEY_TYPE_NORMAL, service=service, notification_type=template.template_type, allow_guest_list_recipients=False, ) postage = None if template.template_type == LETTER_TYPE: # Validate address and set postage to europe|rest-of-world if international letter, # otherwise persist_notification with use template postage postage = validate_address(service, personalisation) if not postage: postage = template.postage validate_created_by(service, post_data['created_by']) sender_id = post_data.get('sender_id', None) reply_to = get_reply_to_text(notification_type=template.template_type, sender_id=sender_id, service=service, template=template) notification = persist_notification( template_id=template.id, template_version=template.version, recipient=post_data['to'], service=service, personalisation=personalisation, notification_type=template.template_type, api_key_id=None, key_type=KEY_TYPE_NORMAL, created_by_id=post_data['created_by'], reply_to_text=reply_to, reference=create_one_off_reference(template.template_type), postage=postage) queue_name = QueueNames.PRIORITY if template.process_type == PRIORITY else None if template.template_type == LETTER_TYPE and service.research_mode: _update_notification_status( notification, NOTIFICATION_DELIVERED, ) else: send_notification_to_queue( notification=notification, research_mode=service.research_mode, queue=queue_name, ) return {'id': str(notification.id)}
def send_pdf_letter_notification(service_id, post_data): service = dao_fetch_service_by_id(service_id) check_service_has_permission(LETTER_TYPE, [p.permission for p in service.permissions]) check_service_over_daily_message_limit(KEY_TYPE_NORMAL, service) validate_created_by(service, post_data['created_by']) validate_and_format_recipient( send_to=post_data['recipient_address'], key_type=KEY_TYPE_NORMAL, service=service, notification_type=LETTER_TYPE, allow_guest_list_recipients=False, ) template = get_precompiled_letter_template(service.id) file_location = 'service-{}/{}.pdf'.format(service.id, post_data['file_id']) try: letter = utils_s3download( current_app.config['TRANSIENT_UPLOADED_LETTERS'], file_location) except S3ObjectNotFound as e: current_app.logger.exception( 'Letter {}.pdf not in transient {} bucket'.format( post_data['file_id'], current_app.config['TRANSIENT_UPLOADED_LETTERS'])) raise e # Getting the page count won't raise an error since admin has already checked the PDF is valid page_count = get_page_count(letter.read()) billable_units = get_billable_units_for_letter_page_count(page_count) personalisation = {'address_line_1': post_data['filename']} notification = persist_notification( notification_id=post_data['file_id'], template_id=template.id, template_version=template.version, recipient=urllib.parse.unquote(post_data['recipient_address']), service=service, personalisation=personalisation, notification_type=LETTER_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL, reference=create_one_off_reference(LETTER_TYPE), client_reference=post_data['filename'], created_by_id=post_data['created_by'], billable_units=billable_units, postage=post_data['postage'] or template.postage, ) upload_filename = get_letter_pdf_filename( reference=notification.reference, crown=notification.service.crown, created_at=notification.created_at, ignore_folder=False, postage=notification.postage) move_uploaded_pdf_to_letters_bucket(file_location, upload_filename) return {'id': str(notification.id)}
def test_should_not_interact_with_cache_for_test_key(sample_service, mocker): mocker.patch('app.notifications.validators.redis_store') check_service_over_daily_message_limit('test', sample_service) assert not app.notifications.validators.redis_store.mock_calls
def test_should_not_interact_with_cache_for_test_key(sample_service, mocker): mocker.patch('app.notifications.validators.redis_store') mocker.patch('app.notifications.validators.redis_store.get', side_effect=[None]) serialised_service = SerialisedService.from_id(sample_service.id) check_service_over_daily_message_limit('test', serialised_service) assert not app.notifications.validators.redis_store.mock_calls