You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by gj...@apache.org on 2021/09/14 12:49:54 UTC
[bloodhound-core] branch main updated: Relax api regex for some
models allowng . in names
This is an automated email from the ASF dual-hosted git repository.
gjm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/bloodhound-core.git
The following commit(s) were added to refs/heads/main by this push:
new 4228632 Relax api regex for some models allowng . in names
4228632 is described below
commit 4228632ce8c124e2bec1f76d83e1252ab5af064a
Author: Gary Martin <gj...@apache.org>
AuthorDate: Tue Sep 14 13:36:50 2021 +0100
Relax api regex for some models allowng . in names
Default api urls do not allow '.' characters when matching the names,
presumably to ensure '.<format>' specifications are definitely matched
properly. This patch relaxes this as we are definitely going to want to
allow for '.' for things like version names.
- change the lookup_value_regex for Component, Milestone and Version
models
- add hypothesis tests for testing the values that the api is allowed
to use for names when creating objects from each list view
---
pyproject.toml | 2 +
trackers/api/serializers.py | 2 -
trackers/api/tests/test_ticket_api.py | 10 +---
trackers/api/tests/test_ticket_api_hyp.py | 84 +++++++++++++++++++++++++++++++
trackers/api/urls.py | 1 -
trackers/api/views.py | 3 ++
6 files changed, 91 insertions(+), 11 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 1eec374..025e0d5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -17,6 +17,8 @@ psycopg2-binary = { version = "^2.9", optional = true }
[tool.poetry.dev-dependencies]
selenium = "^3.141.0"
+django-extensions = "^3.1.3"
+hypothesis = "^6.21.0"
[tool.poetry.extras]
postgres = ["psycopg2"]
diff --git a/trackers/api/serializers.py b/trackers/api/serializers.py
index 58d9248..c8e58cd 100644
--- a/trackers/api/serializers.py
+++ b/trackers/api/serializers.py
@@ -3,8 +3,6 @@ from django.shortcuts import get_object_or_404
from rest_framework import serializers
from rest_framework.reverse import reverse
from ..models import Component, Milestone, Product, Ticket, Version
-from rest_framework_nested.serializers import NestedHyperlinkedModelSerializer
-from rest_framework_nested.relations import NestedHyperlinkedIdentityField
from functools import partial
diff --git a/trackers/api/tests/test_ticket_api.py b/trackers/api/tests/test_ticket_api.py
index b8afb0a..b4e30c0 100644
--- a/trackers/api/tests/test_ticket_api.py
+++ b/trackers/api/tests/test_ticket_api.py
@@ -15,7 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-from django.contrib.auth.models import User
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
@@ -27,12 +26,7 @@ from ...models import (
Ticket,
Version,
)
-from ..serializers import (
- ComponentSerializer,
- MilestoneSerializer,
- TicketSerializer,
- VersionSerializer,
-)
+
class TicketApiTest(APITestCase):
"""Tests for ticket API"""
@@ -313,7 +307,7 @@ class ComponentApiTest(APITestCase):
class MilestoneApiTest(APITestCase):
- """Tests for component API"""
+ """Tests for milestone API"""
def setUp(self):
self.product = Product.objects.create(prefix="BH", name="Bloodhound")
diff --git a/trackers/api/tests/test_ticket_api_hyp.py b/trackers/api/tests/test_ticket_api_hyp.py
new file mode 100644
index 0000000..f54fc50
--- /dev/null
+++ b/trackers/api/tests/test_ticket_api_hyp.py
@@ -0,0 +1,84 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from django.urls import reverse
+from hypothesis import example, given, strategies as st
+from hypothesis.extra.django import TestCase
+from rest_framework.test import APIClient, APIRequestFactory
+from rest_framework import status
+
+from ...models import Product
+
+name_st = st.text(
+ st.characters(
+ blacklist_characters="/",
+ max_codepoint=1000,
+ blacklist_categories=("Cc", "Cs")
+ ),
+ min_size=1
+).map(lambda x: x.strip()).filter(lambda s: len(s) > 0)
+
+
+class CommonAPIPropertiesTestCase(TestCase):
+ """Common tests for API"""
+
+ def setUp(self):
+ self.client = APIClient()
+ self.factory = APIRequestFactory()
+ self.product = Product.objects.create(prefix="BH", name="Bloodhound")
+ self.list_uri = reverse(
+ self.list_view_name,
+ kwargs={"product_prefix": "BH"}
+ )
+
+
+class NameTestsMixin:
+ @given(name=name_st)
+ @example("next 1.x")
+ def test_create(self, name):
+ data = {
+ "name": name,
+ "description": "Example Description",
+ }
+
+ response = self.client.post(self.list_uri, data)
+
+ self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+
+class ComponentAPIPropertiesTest(CommonAPIPropertiesTestCase, NameTestsMixin):
+ """Hypothesis tests for component API"""
+
+ def setUp(self):
+ self.list_view_name = "product-components-list"
+ super().setUp()
+
+
+class MilestoneAPIPropertiesTest(CommonAPIPropertiesTestCase, NameTestsMixin):
+ """Hypothesis tests for milestone API"""
+
+ def setUp(self):
+ self.list_view_name = "product-milestones-list"
+ super().setUp()
+
+
+class VersionAPIPropertiesTest(CommonAPIPropertiesTestCase, NameTestsMixin):
+ """Hypothesis tests for version API"""
+
+ def setUp(self):
+ self.list_view_name = "product-versions-list"
+ super().setUp()
diff --git a/trackers/api/urls.py b/trackers/api/urls.py
index 7dad774..403ea05 100644
--- a/trackers/api/urls.py
+++ b/trackers/api/urls.py
@@ -18,7 +18,6 @@
from django.urls import path
from django.conf.urls import include
from rest_framework.schemas import get_schema_view
-from rest_framework.renderers import JSONOpenAPIRenderer
from rest_framework_nested import routers
from . import views
diff --git a/trackers/api/views.py b/trackers/api/views.py
index 9bacff7..91ceabd 100644
--- a/trackers/api/views.py
+++ b/trackers/api/views.py
@@ -63,6 +63,7 @@ class ComponentViewSet(viewsets.ModelViewSet):
queryset = models.Component.objects.all()
serializer_class = serializers.ComponentSerializer
lookup_field = 'name'
+ lookup_value_regex = '[^/]+'
def get_queryset(self, *args, **kwargs):
prefix = self.kwargs['product_prefix']
@@ -73,6 +74,7 @@ class MilestoneViewSet(viewsets.ModelViewSet):
queryset = models.Milestone.objects.all()
serializer_class = serializers.MilestoneSerializer
lookup_field = 'name'
+ lookup_value_regex = '[^/]+'
def get_queryset(self, *args, **kwargs):
prefix = self.kwargs['product_prefix']
@@ -83,6 +85,7 @@ class VersionViewSet(viewsets.ModelViewSet):
queryset = models.Version.objects.all()
serializer_class = serializers.VersionSerializer
lookup_field = 'name'
+ lookup_value_regex = '[^/]+'
def get_queryset(self, *args, **kwargs):
prefix = self.kwargs['product_prefix']