Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Alternate Repository Location for PEP 708 #15716

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
11 changes: 11 additions & 0 deletions tests/common/db/packaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from warehouse.observations.models import ObservationKind
from warehouse.packaging.models import (
AlternateRepository,
Dependency,
DependencyKind,
Description,
Expand Down Expand Up @@ -200,3 +201,13 @@ class Meta:
)
name = factory.Faker("pystr", max_chars=12)
prohibited_by = factory.SubFactory(UserFactory)


class AlternateRepositoryFactory(WarehouseFactory):
class Meta:
model = AlternateRepository

name = factory.Faker("word")
url = factory.Faker("uri")
description = factory.Faker("text")
project = factory.SubFactory(ProjectFactory)
72 changes: 51 additions & 21 deletions tests/unit/api/test_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
from pyramid.testing import DummyRequest

from warehouse.api import simple
from warehouse.packaging.utils import API_VERSION
from warehouse.packaging.utils import API_VERSION, _valid_simple_detail_context
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't changed the API_VERSION to 1.2, as I wasn't sure if or how PyPI presents different versions of APIs?


from ...common.db.accounts import UserFactory
from ...common.db.packaging import (
AlternateRepositoryFactory,
FileFactory,
JournalEntryFactory,
ProjectFactory,
Expand All @@ -48,29 +49,30 @@ def test_defaults_text_html(self, header):
default to text/html.
"""
request = DummyRequest(accept=header)
assert simple._select_content_type(request) == "text/html"
assert simple._select_content_type(request) == simple.MIME_TEXT_HTML

@pytest.mark.parametrize(
"header, expected",
[
("text/html", "text/html"),
(simple.MIME_TEXT_HTML, simple.MIME_TEXT_HTML),
(
"application/vnd.pypi.simple.v1+html",
"application/vnd.pypi.simple.v1+html",
simple.MIME_PYPI_SIMPLE_V1_HTML,
simple.MIME_PYPI_SIMPLE_V1_HTML,
),
(
"application/vnd.pypi.simple.v1+json",
"application/vnd.pypi.simple.v1+json",
simple.MIME_PYPI_SIMPLE_V1_JSON,
simple.MIME_PYPI_SIMPLE_V1_JSON,
),
(
"text/html, application/vnd.pypi.simple.v1+html, "
"application/vnd.pypi.simple.v1+json",
"text/html",
f"{simple.MIME_TEXT_HTML}, {simple.MIME_PYPI_SIMPLE_V1_HTML}, "
f"{simple.MIME_PYPI_SIMPLE_V1_JSON}",
simple.MIME_TEXT_HTML,
),
(
"text/html;q=0.01, application/vnd.pypi.simple.v1+html;q=0.2, "
"application/vnd.pypi.simple.v1+json",
"application/vnd.pypi.simple.v1+json",
f"{simple.MIME_TEXT_HTML};q=0.01, "
f"{simple.MIME_PYPI_SIMPLE_V1_HTML};q=0.2, "
f"{simple.MIME_PYPI_SIMPLE_V1_JSON}",
simple.MIME_PYPI_SIMPLE_V1_JSON,
),
],
)
Expand All @@ -80,9 +82,9 @@ def test_selects(self, header, expected):


CONTENT_TYPE_PARAMS = [
("text/html", None),
("application/vnd.pypi.simple.v1+html", None),
("application/vnd.pypi.simple.v1+json", "json"),
(simple.MIME_TEXT_HTML, None),
(simple.MIME_PYPI_SIMPLE_V1_HTML, None),
(simple.MIME_PYPI_SIMPLE_V1_JSON, "json"),
]


Expand Down Expand Up @@ -198,12 +200,15 @@ def test_no_files_no_serial(self, db_request, content_type, renderer_override):
user = UserFactory.create()
JournalEntryFactory.create(submitted_by=user)

assert simple.simple_detail(project, db_request) == {
context = {
"meta": {"_last-serial": 0, "api-version": API_VERSION},
"name": project.normalized_name,
"files": [],
"versions": [],
"alternate-locations": [],
}
context = _update_context(context, content_type, renderer_override)
assert simple.simple_detail(project, db_request) == context

assert db_request.response.headers["X-PyPI-Last-Serial"] == "0"
assert db_request.response.content_type == content_type
Expand All @@ -222,13 +227,20 @@ def test_no_files_with_serial(self, db_request, content_type, renderer_override)
db_request.matchdict["name"] = project.normalized_name
user = UserFactory.create()
je = JournalEntryFactory.create(name=project.name, submitted_by=user)
als = [
AlternateRepositoryFactory.create(project=project),
AlternateRepositoryFactory.create(project=project),
]

assert simple.simple_detail(project, db_request) == {
context = {
"meta": {"_last-serial": je.id, "api-version": API_VERSION},
"name": project.normalized_name,
"files": [],
"versions": [],
"alternate-locations": sorted(al.url for al in als),
}
context = _update_context(context, content_type, renderer_override)
assert simple.simple_detail(project, db_request) == context

assert db_request.response.headers["X-PyPI-Last-Serial"] == str(je.id)
assert db_request.response.content_type == content_type
Expand Down Expand Up @@ -258,7 +270,7 @@ def test_with_files_no_serial(self, db_request, content_type, renderer_override)
user = UserFactory.create()
JournalEntryFactory.create(submitted_by=user)

assert simple.simple_detail(project, db_request) == {
context = {
"meta": {"_last-serial": 0, "api-version": API_VERSION},
"name": project.normalized_name,
"versions": release_versions,
Expand All @@ -276,7 +288,10 @@ def test_with_files_no_serial(self, db_request, content_type, renderer_override)
}
for f in files
],
"alternate-locations": [],
}
context = _update_context(context, content_type, renderer_override)
assert simple.simple_detail(project, db_request) == context

assert db_request.response.headers["X-PyPI-Last-Serial"] == "0"
assert db_request.response.content_type == content_type
Expand Down Expand Up @@ -306,7 +321,7 @@ def test_with_files_with_serial(self, db_request, content_type, renderer_overrid
user = UserFactory.create()
je = JournalEntryFactory.create(name=project.name, submitted_by=user)

assert simple.simple_detail(project, db_request) == {
context = {
"meta": {"_last-serial": je.id, "api-version": API_VERSION},
"name": project.normalized_name,
"versions": release_versions,
Expand All @@ -324,7 +339,10 @@ def test_with_files_with_serial(self, db_request, content_type, renderer_overrid
}
for f in files
],
"alternate-locations": [],
}
context = _update_context(context, content_type, renderer_override)
assert simple.simple_detail(project, db_request) == context

assert db_request.response.headers["X-PyPI-Last-Serial"] == str(je.id)
assert db_request.response.content_type == content_type
Expand Down Expand Up @@ -391,7 +409,7 @@ def test_with_files_with_version_multi_digit(
user = UserFactory.create()
je = JournalEntryFactory.create(name=project.name, submitted_by=user)

assert simple.simple_detail(project, db_request) == {
context = {
"meta": {"_last-serial": je.id, "api-version": API_VERSION},
"name": project.normalized_name,
"versions": release_versions,
Expand All @@ -417,11 +435,23 @@ def test_with_files_with_version_multi_digit(
}
for f in files
],
"alternate-locations": [],
}
context = _update_context(context, content_type, renderer_override)
assert simple.simple_detail(project, db_request) == context

assert db_request.response.headers["X-PyPI-Last-Serial"] == str(je.id)
assert db_request.response.content_type == content_type
_assert_has_cors_headers(db_request.response.headers)

if renderer_override is not None:
assert db_request.override_renderer == renderer_override


def _update_context(context, content_type, renderer_override):
if renderer_override != "json" or content_type in [
simple.MIME_TEXT_HTML,
simple.MIME_PYPI_SIMPLE_V1_HTML,
]:
return _valid_simple_detail_context(context)
return context
Loading