Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion ietf/api/tests_views_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.conf import settings
from django.core.files.base import ContentFile
from django.db.models import Max
from django.db.models.functions import Coalesce
from django.test.utils import override_settings
from django.urls import reverse as urlreverse

Expand All @@ -22,7 +23,9 @@ def test_draftviewset_references(self):
viewname = "ietf.api.purple_api.draft-references"

# non-existent draft
bad_id = Document.objects.aggregate(unused_id=Max("id") + 100)["unused_id"]
bad_id = Document.objects.aggregate(unused_id=Coalesce(Max("id"), 0) + 100)[
"unused_id"
]
url = urlreverse(viewname, kwargs={"doc_id": bad_id})
# Without credentials
r = self.client.get(url)
Expand Down
56 changes: 46 additions & 10 deletions ietf/utils/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
from django.template.loaders.filesystem import Loader as BaseLoader
from django.test.runner import DiscoverRunner
from django.core.management import call_command
from django.urls import URLResolver # type: ignore
from django.urls import URLResolver, resolve, Resolver404 # type: ignore
from django.template.backends.django import DjangoTemplates
from django.template.backends.django import Template # type: ignore[attr-defined]
from django.utils import timezone
Expand All @@ -88,6 +88,26 @@
from mypy_boto3_s3.service_resource import Bucket


class UrlCoverageWarning(UserWarning):
"""Warning category for URL coverage-related warnings"""
pass


class UninterestingPatternWarning(UrlCoverageWarning):
"""Warning category for unexpected URL match patterns

These are common, caused by tests that hit a URL that is not selected for
coverage checking. The warning is in place to help with a putative future
review of whether we're selecting the right patterns to check for coverage.
"""
pass


# Configure warnings for reasonable output quantity
warnings.simplefilter("once", UrlCoverageWarning)
warnings.simplefilter("ignore", UninterestingPatternWarning)


loaded_templates: set[str] = set()
visited_urls: set[str] = set()
test_database_name: Optional[str] = None
Expand Down Expand Up @@ -550,21 +570,37 @@ def ignore_pattern(regex, pattern):
)
or pattern.callback == django.views.static.serve)

patterns = [(regex, re.compile(regex, re.U), obj) for regex, obj in url_patterns
if not ignore_pattern(regex, obj)]
patterns ={
regex: obj
for regex, obj in url_patterns
if not ignore_pattern(regex, obj)
}

covered = set()
for url in visited_urls:
for regex, compiled, obj in patterns:
if regex not in covered and compiled.match(url[1:]): # strip leading /
covered.add(regex)
break
try:
resolved = resolve(url) # let Django resolve the URL for us
except Resolver404:
warnings.warn(
f"Unable to resolve visited URL {url}", UrlCoverageWarning
)
continue
if resolved.route not in patterns:
warnings.warn(
f"WARNING: url resolved to an unexpected pattern (url='{url}', "
f"resolved to r'{resolved.route}'",
UninterestingPatternWarning,
)
continue
covered.add(resolved.route)

self.runner.coverage_data["url"] = {
"coverage": 1.0*len(covered)/len(patterns),
"covered": dict( (k, (o.lookup_str, k in covered)) for k,p,o in patterns ),
"coverage": 1.0 * len(covered) / len(patterns),
"covered": dict(
(k, (o.lookup_str, k in covered)) for k, o in patterns.items()
),
"format": 4,
}
}

self.report_test_result("url")
else:
Expand Down
Loading