Skip to content

Commit

Permalink
Serve message schemas.
Browse files Browse the repository at this point in the history
Bodhi now serves its own message schemas at /message-schemas/v1/
so that the URLs referenced in the schemas will not return HTTP
404 codes.

fixes #3083

Signed-off-by: Randy Barlow <randy@electronsweatshop.com>
  • Loading branch information
bowlofeggs authored and mergify[bot] committed Apr 23, 2019
1 parent 5c4cc81 commit 0561675
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 0 deletions.
101 changes: 101 additions & 0 deletions bodhi/server/services/schemas.py
@@ -0,0 +1,101 @@
# Copyright © 2019 Red Hat, Inc.
#
# This file is part of Bodhi.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""Defines service endpoints for our message schemas."""

import typing

from cornice.resource import resource, view
from pyramid import httpexceptions
from pyramid.security import Allow, Everyone
import pkg_resources

from bodhi.server import security
from bodhi.server.services import errors

if typing.TYPE_CHECKING: # pragma: no cover
import pyramid.util.Request # noqa: 401


READ_ACL = 'view_schemas'


@resource(collection_path='/message-schemas/v1/', path='/message-schemas/v1/{topic}',
description='Message schemas')
class MessageSchemasV1:
"""
Defines resources for serving Bodhi's message schemas.
Operations acting on the collection are served at ``/message-schemas/v1/`` and operations acting
on a single schema are served at ``/message-schemas/v1/<topic>``.
"""

def __init__(self, request: 'pyramid.util.Request', context: None = None):
"""
Initialize the MessageSchemas resource.
Args:
request: The current web request.
context: Unused.
"""
self.request = request

@staticmethod
def __acl__() -> typing.Iterable[typing.Tuple[str, str, str]]:
"""
Define ACLs for the MessageSchemas resource.
Returns:
A list of ACLs for this Resource.
"""
return [(Allow, Everyone, READ_ACL)]

@view(
accept=('application/json', 'text/json'), renderer='json',
cors_origins=security.cors_origins_ro, error_handler=errors.json_handler,
permission=READ_ACL)
def collection_get(self) -> typing.Iterable[str]:
"""
List schemas.
This method responds to the ``/message-schemas/v1/`` endpoint.
Returns:
A list of message topics that Bodhi supports.
"""
return [m.load().topic for m in pkg_resources.iter_entry_points('fedora.messages')
if m.module_name.startswith('bodhi.')]

@view(accept=('application/json', 'text/json'), renderer='json',
cors_origins=security.cors_origins_ro, error_handler=errors.json_handler,
permission=READ_ACL)
def get(self) -> dict:
"""
Retrieve and render a single message schema.
This API responses to the ``/message_schemas/v1/<topic>`` endpoint.
Returns:
The requested message schema.
"""
try:
return pkg_resources.load_entry_point(
'bodhi-messages', 'fedora.messages',
f"{self.request.matchdict['topic']}.v1").body_schema
except ImportError:
# The user has requested a topic that does not exist
raise httpexceptions.HTTPNotFound()
84 changes: 84 additions & 0 deletions bodhi/tests/server/services/test_schemas.py
@@ -0,0 +1,84 @@
# Copyright 2019 Red Hat, Inc.
#
# This file is part of Bodhi.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""This module contains tests for bodhi.server.services.schemas."""

from pyramid import testing
from pyramid import security

from bodhi.messages.schemas.update import UpdateCommentV1
from bodhi.server.services import schemas
from bodhi.tests.server import base


class TestMessageSchemasV1__init__(base.BaseTestCase):
"""This class contains tests for the MessageSchemasV1.__init__() method."""
def test___init__(self):
"""Assert the request is stored properly."""
request = testing.DummyRequest()

schemas_resource = schemas.MessageSchemasV1(request)

self.assertIs(schemas_resource.request, request)


class TestMessageSchemasV1__acl__(base.BaseTestCase):
"""This class contains tests for the MessageSchemasV1.__acl__() method."""
def test___acl__(self):
"""Assert the permissions are correct."""
request = testing.DummyRequest()
schemas_resource = schemas.MessageSchemasV1(request)

acls = schemas_resource.__acl__()

self.assertEqual(acls, [(security.Allow, security.Everyone, 'view_schemas')])


class TestMessageSchemasV1CollectionGet(base.BaseTestCase):
"""This class contains tests for the MessageSchemasV1.collection_get() method."""
def test_get(self):
"""Test with a GET request."""
response = self.app.get('/message-schemas/v1/', status=200, headers={'Accept': 'text/json'})

self.assertEqual(
set(response.json),
set([
'bodhi.buildroot_override.tag', 'bodhi.buildroot_override.untag',
'bodhi.compose.complete', 'bodhi.compose.composing', 'bodhi.compose.start',
'bodhi.compose.sync.done', 'bodhi.compose.sync.wait', 'bodhi.composer.start',
'bodhi.errata.publish', 'bodhi.repo.done', 'bodhi.update.comment',
'bodhi.update.complete.stable', 'bodhi.update.complete.testing',
'bodhi.update.edit', 'bodhi.update.eject', 'bodhi.update.karma.threshold.reach',
'bodhi.update.request.obsolete', 'bodhi.update.request.revoke',
'bodhi.update.request.stable', 'bodhi.update.request.testing',
'bodhi.update.request.unpush', 'bodhi.update.requirements_met.stable']))


class TestMessageSchemasV1Get(base.BaseTestCase):
"""This class contains tests for the MessageSchemasV1.get() method."""
def test_404(self):
"""Assert a 404 error code when there isn't a message topic matching the URL."""
self.app.get('/message-schemas/v1/does-not-exist', status=404,
headers={'Accept': 'text/json'})

def test_200(self):
"""Assert correct behavior when an existing topic is requested."""
response = self.app.get(
'/message-schemas/v1/bodhi.update.comment',
status=200, headers={'Accept': 'text/json'})

self.assertEqual(response.json, UpdateCommentV1.body_schema)
1 change: 1 addition & 0 deletions docs/server_api/index.rst
Expand Up @@ -45,6 +45,7 @@ sections of the API by following the links below:
rest/overrides
rest/packages
rest/releases
rest/schemas
rest/updates
rest/users

Expand Down
10 changes: 10 additions & 0 deletions docs/server_api/rest/schemas.rst
@@ -0,0 +1,10 @@
Message schemas
===============

``cornice_sphinx`` does `not <https://github.com/Cornices/cornice.ext.sphinx/issues/15>`_ yet have
the ability to render documentation for the ``/message-schemas/`` API, so we will include docblock
documentation for that service here instead.


.. autoclass:: bodhi.server.services.schemas.MessageSchemasV1
:members:

0 comments on commit 0561675

Please sign in to comment.