Example #1
0
    def _get_existing_database(self,
                               database_id: int,
                               schema: str = None) -> Database:
        """Returns the database object for an existing database

        Keyword arguments:
        database_id -- the ID used to identify the database
        schema -- the schema to be used

        Raises:
            SchemaNotAllowedCsvUploadException: If the schema is not allowed for csv upload
            GetDatabaseException:    1. If the database ID is not valid
                                     2. If there was a problem getting the schema
            NoResultFound: If no database found with id
            MultipleResultsFound: If more than one database found with id
        """
        try:
            database = db.session.query(Database).filter_by(
                id=database_id).one()
            if not self._is_schema_allowed_for_csv_upload(database, schema):
                message = _(
                    f"Database {database.database_name} Schema {schema} is not allowed for csv uploads. "
                    "Please contact your Superset administrator.")
                raise SchemaNotAllowedCsvUploadException(message, None)
            return database
        except NoResultFound as e:
            raise NoResultFound("Database was not found.", e)
        except MultipleResultsFound as e:
            raise MultipleResultsFound("Multiple databases were found.", e)
        except SchemaNotAllowedCsvUploadException as e:
            raise e
        except Exception as e:
            raise GetDatabaseException(
                "An unknown error occurred trying to get the database.", e)
Example #2
0
 def test013_load_from_ext_id_multiple(self):
     m_session = MagicMock()
     external_id = "whatever"
     m_filter = m_session.query().options().filter
     m_filter.side_effect = MultipleResultsFound()
     with self.assertRaises(IrmaDatabaseError):
         Scan.load_from_ext_id(external_id, m_session)
 def one(self) -> Any:
     if len(self._result) == 1:
         return self._result[0]
     elif self._result:
         raise MultipleResultsFound("Multiple rows returned for one()")
     else:
         raise NoResultFound("No rows returned for one()")
    def createUser(self, username):
        """ Creates a new entry for new usernames, if a user is found with this email that has not yet registered, just returns that user's ID.  Raises an exception if multiple results found, or if user has already registered.

        Arguments:
        username - username to find or create an id for
        Returns:
        user object
        """
        # Check if user exists
        queryResult = self.session.query(User).options(joinedload("user_status")).filter(User.username == username).all()
        if(len(queryResult) == 1):
            # If so, check their status
            user = queryResult[0]
            if(user.user_status.name == "awaiting_confirmation" or user.user_status.name == "email_confirmed"):
                # User has not yet registered, may restart process
                return user
        elif(len(queryResult) == 0):
            # If not, add new user
            newUser = User(username = username)
            self.session.add(newUser)
            self.session.commit()
            return newUser
        else:
            # Multiple entries for this user, server error
            raise MultipleResultsFound("Multiple entries for single username")
Example #5
0
def _insert_url(session, url):
    """ insert into table Page if not exist and return the url id
	Args:
		url(str): wiki url to update

	Returns:
		int: url id

	Raise:
		DisconnectionError
		MultipleResultsFound
	"""
    try:

        if session.query(Page.id).filter_by(url=url).scalar() is None:
            page = Page(url=url)
            session.add(page)
            session.commit()
            url_id = session.query(Page).filter_by(url=url).first().id
            _insert_link(session, url_id, url_id, 0)

    except DisconnectionError:
        raise DisconnectionError("There is error with DB connection")

    except MultipleResultsFound:
        raise MultipleResultsFound("Many rows found in DB to find url \
									id of {}".format(url))

    url_id = session.query(Page.id).filter_by(url=url).first()

    return url_id.id
Example #6
0
    def find_or_create(cls, session, namespace_id, name, display_name, type_):
        name = name or ''

        objects = session.query(cls).filter(
            cls.namespace_id == namespace_id,
            cls.display_name == display_name).all()

        if not objects:
            obj = cls(namespace_id=namespace_id,
                      name=name,
                      display_name=display_name,
                      type_=type_,
                      deleted_at=EPOCH)
            session.add(obj)
        elif len(objects) == 1:
            obj = objects[0]
            if not obj.name:
                # There is an existing category with this `display_name` and no
                # `name`, so update it's `name` as needed.
                # This is needed because the first time we sync generic IMAP
                # folders, they may initially have `name` == '' but later they may
                # get a `name`. At this point, it *is* the same folder so we
                # merely want to update its `name`, not create a new one.
                obj.name = name
        else:
            log.error('Duplicate category rows for namespace_id {}, '
                      'name {}, display_name: {}'.format(
                          namespace_id, name, display_name))
            raise MultipleResultsFound(
                'Duplicate category rows for namespace_id {}, name {}, '
                'display_name: {}'.format(namespace_id, name, display_name))

        return obj
Example #7
0
def lookup(session, model, **attrs):
    """
    Find a unique object identified by a set of attributes.

    :param session: An SQLAlchemy session
    :param model: An SQLAlchemy model to find
    :param attrs:
        A set of column names and values to use for matching.
    """
    conditions = tuple(getattr(model, attr) == attrs[attr] for attr in attrs)
    filter_cond = and_(*conditions)

    query = session.query(model).filter(filter_cond)
    num = query.count()
    if num == 1:
        obj = query.first()
        logger.debug('found %r object %r', model, obj)
        return obj
    elif num == 0:
        raise NoResultFound("No results for %r with condition %r" %
                            (model, filter_cond))
    else:
        raise MultipleResultsFound(
            "Multiple results (%d) for %r with condition %r" %
            (num, model, filter_cond))
Example #8
0
 def test_classmethod_load_from_sha256_raise_MultipleResultNotFound(self):  # nopep8
     sample = "test"
     session = MagicMock()
     session.query.side_effect = MultipleResultsFound(sample)
     with self.assertRaises(IrmaDatabaseError) as context:
         module.File.load_from_sha256("whatever", session)
     self.assertEqual(str(context.exception), sample)
 def scalar(self) -> Any:
     if len(self._result) == 1:
         row = self._result[0]
         return row[0]
     elif self._result:
         raise MultipleResultsFound(
             "Multiple rows were found when exactly one was required")
     return None
Example #10
0
    def is_run(filename):
        migration = SESSION.query(SchemaMigration).filter(
            SchemaMigration.migration_file == filename)
        if migration.count() > 1:
            raise MultipleResultsFound(
                'Multiple migration files found with specified name.')

        return migration.first().run_status
 def one_or_none(self) -> Optional[Any]:
     if len(self._result) == 1:
         return self._result[0]
     elif self._result:
         raise MultipleResultsFound(
             "Multiple rows returned for one_or_none()")
     else:
         return None
    def find_one(cls, **kwargs):
        result = cls.find(**kwargs)

        if not result:
            raise NoResultFound("No {} found for query:{}".format(cls.__name__, kwargs))
        elif len(result) > 1:
            raise MultipleResultsFound("More than one {} found for query:{}".format(cls.__name__, kwargs))
        else:
            return result[0]
Example #13
0
    def search(lcid):
        try:
            query = sessions[lcid].query(Type)
            if search_word.isdigit():
                types = query.filter_by(id=search_word)
            else:
                types = query.filter(Type.name.contains(search_word))

            update_results2description(lcid, types.one())
        except MultipleResultsFound:
            if types.count() > config.search_limit:
                raise MultipleResultsFound()
            else:
                html = ''
                groups = collections.OrderedDict()

                list_lorder = lorder.load('list.html')

                for type_ in types.all():
                    group = type_.group

                    if group not in groups:
                        groups[group] = []

                    if lcid == config.default_lcid:
                        groups[group].append(type_)
                    else:
                        default_type = sessions[config.default_lcid].query(Type) \
                                        .filter_by(id=type_.id).one()
                        groups[group].append(default_type)

                for group, types_ in groups.items():
                    name = group.name
                    try:
                        locale_group = sessions[config.lcid].query(Group) \
                                        .filter_by(id=group.id).one()
                        name = '%s(%s)' % (locale_group.name, group.name)
                    except:
                        pass

                    kwargs = {
                        'name': name,
                        'items': create_list_items(Type, types_, '/type/'),
                    }

                    html += tornado.escape.to_basestring(
                        list_lorder.generate(kwargs=update_template_kwargs(kwargs))
                    )
                    html += '<hr />'

                results['content'] = html
                results['name'] = search_word
                results['search_word'] = search_word
        except NoResultFound:
            return False

        return True
Example #14
0
def get_scalar(rows: Sequence[Any]) -> Any:
    """Utility for mocking sqlalchemy.orm.Query.scalar()."""
    if len(rows) == 1:
        try:
            return rows[0][0]
        except TypeError:
            return rows[0]
    elif len(rows) > 1:
        raise MultipleResultsFound(
            "Multiple rows were found when exactly one was required"
        )
    return None
Example #15
0
 def get(cls, id):
     try:
         result = db_session.query(cls).filter_by(id=id).one()
     except MultipleResultsFound:
         msg = 'There are multiple {} records with the same id={}!'.format(cls.__name__, id)
         log.critical(msg)
         raise MultipleResultsFound(msg)
     except NoResultFound:
         msg = 'There is no record {} with id={}!'.format(cls.__name__, id)
         log.debug(msg)
         raise NoResultFound(msg)
     else:
         return result
Example #16
0
 def find_by_name(cls, name):
     try:
         result = db_session.query(cls).filter_by(name=name).one()
     except MultipleResultsFound:
         # Theoretically cannot happen because of model built-in constraints
         msg = 'Multiple command segments with identical names has been found!'
         log.critical(msg)
         raise MultipleResultsFound(msg)
     except NoResultFound:
         msg = 'There is no command segment with name={}!'.format(name)
         log.warning(msg)
         raise NoResultFound(msg)
     else:
         return result
Example #17
0
    def checkUserInDb(self, request, claims):
        idUser = claims.get('sub')
        query = request.dbsession.query(
            TUsers.TUse_PK_ID, TUsers.TUse_LastName, TUsers.TUse_FirstName,
            TUsers.TUse_CreationDate, TUsers.TUse_Login, TUsers.TUse_Language,
            TUsers.TUse_ModificationDate, TUsers.TUse_HasAccess,
            TUsers.TUse_Photo, TUsers.TUse_PK_ID_OLD)
        query = query.filter(TUsers.TUse_PK_ID == idUser)
        try:
            res = query.one_or_none()
            return TUsersSchema().dump(res) if res else None
        except MultipleResultsFound:
            raise MultipleResultsFound()

        return res
Example #18
0
def update_row_by_id(session: Session, model: DeclarativeMeta, id: int,
                     updates: dict):
    """
    update the fields of a row with the particular primary key
    Parameters
    ----------
    session
        sqlalchemy.orm.session.Session
        session object to be used
    model
        sqlalchemy.ext.declarative.DeclarativeMeta
        the sqlalchemy model to use
    id
        int
        the primary key
    updates
        dict
        the fields to update as the keys and their respective values and the dictionary values
    """

    if not isinstance(updates, dict):
        raise TypeError('updates must be of type dict')

    query = read_row_by_id(session, model, id)

    try:
        query.one()
    except NoResultFound as e:
        raise NoResultFound(
            f"row cannot be updated because no row can be found with id: {id}")
    except MultipleResultsFound as e:
        raise MultipleResultsFound(
            f"the database contains multiple results for this id when only one is expected. id: {id}"
        )

    matched = query.update(updates)

    if matched == 0:
        raise ValueError(
            f"bad update request, no columns could be matched updates requested: {json.dumps(updates)}"
        )
    try:
        session.commit()
        session.flush()
    except Exception as e:
        session.rollback()
        session.flush()
        raise e
Example #19
0
    def test_multiple_product_groups(self, User):
        from sqlalchemy.orm.exc import MultipleResultsFound
        user = mock.Mock()
        user.id = 1
        user.email = '*****@*****.**'
        p = mock.PropertyMock(side_effect=MultipleResultsFound('Boom!'))
        type(user).product_group = p
        User.get_all.return_value = [
            user,
        ]

        from pyramid_bimt.sanitycheck import CheckUsersProductGroup
        self.assertEqual(
            CheckUsersProductGroup()(),
            ['User [email protected] (1) has multiple product groups.'],
        )
Example #20
0
    def find_one(cls, **kwargs):
        '''
        Wrapper of find() that return a single result.
        Will error if None or more then one results found.
        '''
        result = cls.find(**kwargs)

        if not result:
            raise NoResultFound("No {} found for query:{}".format(
                cls.__name__, kwargs))
        elif len(result) > 1:
            raise MultipleResultsFound(
                "More than one {} found for query:{}".format(
                    cls.__name__, kwargs))
        else:
            return result[0]
    def get_ori_identifier(self, iri):
        """
        Retrieves a Resource-based ORI identifier from the database. If no corresponding Resource exists,
        a new one is created.
        """

        session = self.Session()
        try:
            resource = session.query(Resource).join(Source).filter(
                Source.iri == iri).one()
            return Uri(Ori, resource.ori_id)
        except MultipleResultsFound:
            raise MultipleResultsFound('Multiple resources found for IRI %s' %
                                       iri)
        except NoResultFound:
            return self.generate_ori_identifier(iri=iri)
        finally:
            session.close()
Example #22
0
def get_category_by_name(session, name):
    '''
        Get the category matching a name.
        - Category name can be a simple name, or a full path to a category
          inside the Category hierarchy.
        - A full path consists of a sequence of category names separated by
          '->' e.g. 'Refined->Gasoline'
    '''
    full_path = name.split('->')
    if len(full_path) > 1:
        # traverse the path
        try:
            cat_obj = (session.query(Category).filter(
                Category.name == full_path[0]).filter(
                    Category.parent == None).one())

            for cat_name in full_path[1:]:
                matching_catlist = [
                    c for c in cat_obj.children if c.name == cat_name
                ]

                if len(matching_catlist) > 1:
                    raise MultipleResultsFound('One matching child Category '
                                               'required, found {} categories '
                                               'matching the name {}'.format(
                                                   len(matching_catlist),
                                                   cat_name))
                elif len(matching_catlist) == 0:
                    raise NoResultFound('child Category matching the name {} '
                                        'not found'.format(cat_name))

                cat_obj = matching_catlist[0]
        except Exception:
            cat_obj = None
    else:
        # just a simple name
        try:
            cat_obj = (session.query(Category).filter(
                Category.name == name).one())
        except Exception:
            cat_obj = None

    return cat_obj
    def get_mergeable_resource_identifier(self, model_object, predicate,
                                          column, value):
        """
        Queries the database to find the ORI identifier of the Resource linked to the Property with the given
        predicate and value in the specified column.
        """

        definition = model_object.definition(predicate)

        session = self.Session()
        try:
            query_result = session.query(Property).filter(
                Property.predicate == definition.absolute_uri())
            if column == 'prop_resource':
                query_result = query_result.filter(
                    Property.prop_resource == value)
            elif column == 'prop_string':
                query_result = query_result.filter(
                    Property.prop_string == value)
            elif column == 'prop_datetime':
                query_result = query_result.filter(
                    Property.prop_datetime == value)
            elif column == 'prop_integer':
                query_result = query_result.filter(
                    Property.prop_integer == value)
            elif column == 'prop_url':
                query_result = query_result.filter(Property.prop_url == value)
            else:
                raise ValueError(
                    'Invalid column type "%s" specified for merge_into' %
                    column)
            resource_property = query_result.one()
            return resource_property.resource.iri
        except MultipleResultsFound:
            raise MultipleResultsFound(
                'Multiple resources found for predicate "%s" with value "%s" in column "%s"'
                % (predicate, value, column))
        except NoResultFound:
            raise NoResultFound(
                'No resource found for predicate "%s" with value "%s" in column "%s"'
                % (predicate, value, column))
        finally:
            session.close()
    def get_rov_sol(cls, roverparam, sol):
        """Return photo data for a given Rover and mission sol."""
        try:
            rover = DBSession.query(Rover).filter_by(name=roverparam).one()
        except NoResultFound:
            raise NoResultFound("Invalid rover name")

        except MultipleResultsFound:
            raise MultipleResultsFound("How did you even do that?")

        return_dict = {}
        # finds absolute last day in which this rover has photos.
        maxsol_tuple = DBSession.query(func.max(
            Photo.sol)).filter(Photo.rover_name == roverparam).one()
        maxsol = maxsol_tuple[0]
        if not maxsol:
            raise ValueError("No photos for your rover in database")

        if sol > maxsol:
            sol = maxsol

        while sol < maxsol:
            if rover.photos.filter(Photo.sol == sol).first():
                break
            sol += 1

        return_dict['rover'] = rover.name
        return_dict['sol'] = sol
        return_dict['photos_by_cam'] = {}
        return_dict['last_day'] = True if sol >= maxsol else False
        return_dict['first_day'] = True if sol <= 1 else False

        for cam in rover.cameras:
            photos_query = cam.photos.filter(Photo.sol == sol)
            photos_query = filter_only_left(photos_query, roverparam)
            photos_query = filter_bad_quality(photos_query, roverparam)
            photos_query = order_photo_query(photos_query)
            return_dict['photos_by_cam'][cam.name] = photos_query.all()

        return return_dict
Example #25
0
def fetch_all_first_values(session: Session,
                           select_statement: Select) -> List[Any]:
    """
    Returns a list of the first values in each row returned by a ``SELECT``
    query.

    A Core version of this sort of thing:
    http://xion.io/post/code/sqlalchemy-query-values.html

    Args:
        session: SQLAlchemy :class:`Session` object
        select_statement: SQLAlchemy :class:`Select` object

    Returns:
        a list of the first value of each result row

    """
    rows = session.execute(select_statement)  # type: ResultProxy
    try:
        return [row[0] for row in rows]
    except ValueError as e:
        raise MultipleResultsFound(str(e))
    def test_take_action_multiple(self, m_dev_obj):

        # remove ShowOne from the DeviceShow inheritance
        bases = copy(ds.DeviceShow.__bases__)
        f_bases = tuple(base for base in bases if base != ShowOne)

        m_args = mock.Mock()
        m_args._get_kwargs.return_value = {'detailed': None}

        m_dev_obj.find.side_effect = MultipleResultsFound()

        m_base = mock.patch.object(ds.DeviceShow, '__bases__', f_bases)
        with m_base:
            m_base.is_local = True
            t_device = dss.DeviceShowSerial()

            t_device.app = mock.Mock()

            self.assertRaises(RuntimeWarning, t_device.take_action, m_args)

        # ensure that is_local on the patch does not modify the actual bases
        self.assertEqual(bases, ds.DeviceShow.__bases__)
Example #27
0
def _insert_link(session, from_page_id, to_page_id, no_of_separation):
    """ insert link into database if link is not existed

	Args:
		from_page_id(int): id of "from" page
    	to_page_id(int): id of "to" page
		no_of_separation(int)

	Returns:
		None

	Raise
		DisconnectionError
		MultipleResultsFound
	"""

    try:

        if session.query(Link).filter_by(
                from_page_id=from_page_id,
                to_page_id=to_page_id,
                number_of_separation=no_of_separation).scalar() is None:

            link = Link(from_page_id=from_page_id,
                        to_page_id=to_page_id,
                        number_of_separation=no_of_separation)

            session.add(link)
            session.commit()

    except DisconnectionError:
        raise DisconnectionError("There is error with DB connection")

    except MultipleResultsFound:
        raise MultipleResultsFound(
            "Many rows found in DB to store link from {} to {}\
			 with number of seperation {}".format(from_page_id, to_page_id,
                                         no_of_separation))
Example #28
0
def get_or_create(session, model, **attrs):
    """
    Find or create a unique object identified by a set of attributes.

    .. note::
        Created objects are not added to the database session, so this function
        is is really only useful if you *know* you're going to mutate the
        result.

        Otherwise you'll have to check the object state to figure out
        if it needs to be added to the database session
        (https://docs.sqlalchemy.org/en/latest/orm/session_state_management.html),
        and at that point it might be easier to *not* use this function.

    :param session: An SQLAlchemy session
    :param model: An SQLAlchemy model to find
    :param attrs:
        A set of column names and values to use for matching. If a matching
        object is not found, it will be created using these values.
    """
    conditions = tuple(getattr(model, attr) == attrs[attr] for attr in attrs)
    filter_cond = and_(*conditions)

    query = session.query(model).filter(filter_cond)
    num = query.count()
    if num == 0:
        obj = model(**attrs)
        logger.debug('created new %r object %r', model, obj)
        return obj
    elif num == 1:
        obj = query.first()
        logger.debug('found existing %r object %r', model, obj)
        return obj
    else:
        raise MultipleResultsFound(
            "Multiple results (%d) for %r with condition %r" %
            (num, model, filter_cond))
    mock_update_notification_status.assert_called_with(notification, notify_status)


def test_govdelivery_callback_returns_200(
        client,
        mock_dao_get_notification_by_reference,
        mock_map_govdelivery_status_to_notify_status,
        mock_update_notification_status,
):
    response = post(client, get_govdelivery_request("123456", "sent"))

    assert response.status_code == 200


@pytest.mark.parametrize("exception", [MultipleResultsFound(), NoResultFound()])
def test_govdelivery_callback_always_returns_200_after_expected_exceptions(
        client,
        mock_dao_get_notification_by_reference,
        mock_map_govdelivery_status_to_notify_status,
        mock_update_notification_status,
        exception
):
    mock_dao_get_notification_by_reference.side_effect = exception

    response = post(client, get_govdelivery_request("123456", "sent"))

    assert response.status_code == 200


def test_govdelivery_callback_raises_invalid_request_if_missing_data(client):
class TestProcessSNSDeliveryStatus:
    @pytest.mark.skip(reason="Endpoint disabled and slated for removal")
    @pytest.mark.parametrize('data', [
        payload_with_missing_message_id(),
        payload_with_missing_status(),
        get_sns_delivery_status_payload(create_uuid(), "NOT_A_VALID_STATE"),
        get_sns_delivery_status_payload("not-uuid", SNS_STATUS_SUCCESS)
    ])
    def test_returns_bad_request_on_schema_validation_errors(
            self, client, data):
        response = post(client, data)
        assert response.status_code == 400

    @pytest.mark.skip(reason="Endpoint disabled and slated for removal")
    def test_loads_notification_by_reference(
            self, client, mock_notification,
            mock_dao_get_notification_by_reference,
            mock_update_notification_status, mock_process_service_callback):
        mock_dao_get_notification_by_reference.return_value = mock_notification
        post(
            client,
            get_sns_delivery_status_payload(mock_notification.reference,
                                            SNS_STATUS_SUCCESS))

        mock_dao_get_notification_by_reference.assert_called_with(
            mock_notification.reference)

    @pytest.mark.skip(reason="Endpoint disabled and slated for removal")
    @pytest.mark.parametrize(
        "exception",
        [MultipleResultsFound(), NoResultFound()])
    def test_returns_404_when_unable_to_load_notification(
            self, client, mock_notification,
            mock_dao_get_notification_by_reference, exception):
        mock_dao_get_notification_by_reference.side_effect = exception
        response = post(
            client,
            get_sns_delivery_status_payload(mock_notification.reference,
                                            SNS_STATUS_SUCCESS))

        assert response.status_code == 404

    @pytest.mark.skip(reason="Endpoint disabled and slated for removal")
    @pytest.mark.parametrize("sns_status, status",
                             [(SNS_STATUS_SUCCESS, NOTIFICATION_SENT),
                              (SNS_STATUS_FAILURE, NOTIFICATION_FAILED)])
    def test_should_update_notification_status(
            self, client, mock_notification,
            mock_dao_get_notification_by_reference,
            mock_update_notification_status, mock_process_service_callback,
            sns_status, status):
        mock_dao_get_notification_by_reference.return_value = mock_notification
        post(
            client,
            get_sns_delivery_status_payload(mock_notification.reference,
                                            sns_status))

        mock_update_notification_status.assert_called_with(
            mock_notification, status)

    @pytest.mark.skip(reason="Endpoint disabled and slated for removal")
    def test_should_process_service_callback(
        self,
        client,
        mock_notification,
        mock_dao_get_notification_by_reference,
        mock_update_notification_status,
        mock_process_service_callback,
    ):
        mock_dao_get_notification_by_reference.return_value = mock_notification
        mock_update_notification_status.return_value = mock_notification
        post(
            client,
            get_sns_delivery_status_payload(mock_notification.reference,
                                            SNS_STATUS_SUCCESS))

        mock_process_service_callback.assert_called_with(mock_notification)

    @pytest.mark.skip(reason="Endpoint disabled and slated for removal")
    def test_should_send_callback_metrics(
            self, client, mock_notification,
            mock_dao_get_notification_by_reference,
            mock_update_notification_status, mock_process_service_callback,
            mock_send_callback_metrics):
        mock_dao_get_notification_by_reference.return_value = mock_notification
        mock_update_notification_status.return_value = mock_notification
        post(
            client,
            get_sns_delivery_status_payload(mock_notification.reference,
                                            SNS_STATUS_SUCCESS))

        mock_send_callback_metrics.assert_called_with(mock_notification)

    @pytest.mark.skip(reason="Endpoint disabled and slated for removal")
    def test_returns_204(
        self,
        client,
        mock_notification,
        mock_dao_get_notification_by_reference,
        mock_update_notification_status,
        mock_process_service_callback,
    ):
        mock_dao_get_notification_by_reference.return_value = mock_notification
        mock_update_notification_status.return_value = mock_notification
        response = post(
            client,
            get_sns_delivery_status_payload(mock_notification.reference,
                                            SNS_STATUS_SUCCESS))

        assert response.status_code == 204