Skip to content
Permalink
Browse files
Add product model and api tests
 - added product model
 - adds basic api and api tests for product
  • Loading branch information
Gary Martin committed May 15, 2021
1 parent a840d8e commit dc439b7433ae52367099f2f4c4ab7a7ba47ec4f0
Showing 16 changed files with 348 additions and 62 deletions.
@@ -145,6 +145,5 @@

REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
]
],
}
@@ -36,5 +36,6 @@

urlpatterns = [
path('', include('trackers.urls')),
path('api-auth/', include('rest_framework.urls')),
path('admin/', admin.site.urls),
]
@@ -21,19 +21,33 @@
import unittest


class TicketViewTest(unittest.TestCase):
class HomePageViewTest(unittest.TestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)

def tearDown(self):
self.browser.quit()

def test_user_can_add_view_and_delete_ticket(self):
def test_user_can_see_homepage(self):
self.browser.get('http://localhost:8000')

self.assertIn('Bloodhound', self.browser.title)


class ApiHomePageViewTest(unittest.TestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)

def tearDown(self):
self.browser.quit()

def test_user_can_see_api_homepage(self):
self.browser.get('http://localhost:8000/api')

self.assertIn('Api Root', self.browser.title)


if __name__ == '__main__':
unittest.main(warnings='ignore')
@@ -0,0 +1,16 @@
# 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.
@@ -1,6 +1,7 @@
from django.contrib.auth.models import User, Group
from rest_framework import serializers
from trackers import models
from ..models import Product


class UserSerializer(serializers.HyperlinkedModelSerializer):
@@ -15,6 +16,12 @@ class Meta:
fields = ('url', 'name')


class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'


class TicketSerializer(serializers.ModelSerializer):
api_url = serializers.SerializerMethodField()
api_events_url = serializers.SerializerMethodField()
@@ -0,0 +1,16 @@
# 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.
@@ -0,0 +1,112 @@
# 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.contrib.auth.models import User
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status

from ...models import Product
from ..serializers import ProductSerializer


class ProductsApiTest(APITestCase):
"""Test for GET all products API """
def setUp(self):
self.ally = Product.objects.create(prefix='ALY', name='Project Alice')
self.bob = Product.objects.create(prefix='BOB', name='Project Robert')

self.new_product_data = {
'prefix': 'CAR',
'name': 'Project Caroline',
}

self.product_data = {
'prefix': self.ally.prefix,
'name': 'Project Alan',
}

self.bad_product_data = {
'prefix': self.bob.prefix,
'name': '',
}

def test_get_all_products(self):
response = self.client.get(reverse('product-list'))
products = Product.objects.all()
serializer = ProductSerializer(products, many=True)
self.assertEqual(response.data, serializer.data)
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_get_product(self):
response = self.client.get(
reverse('product-detail', args=[self.ally.prefix])
)
product = Product.objects.get(prefix=self.ally.prefix)
serializer = ProductSerializer(product)
self.assertEqual(response.data, serializer.data)
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_get_invalid_product(self):
response = self.client.get(
reverse('product-detail', args=['randomnonsense'])
)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

def test_create_product(self):
response = self.client.post(
reverse('product-list'),
self.new_product_data,
)
product = Product.objects.get(prefix=self.new_product_data['prefix'])
serializer = ProductSerializer(product)

self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data, serializer.data)

def test_create_bad_product(self):
response = self.client.post(
reverse('product-list'),
self.bad_product_data,
)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

def test_update_product(self):
response = self.client.put(
reverse('product-detail', args=[self.ally.prefix]),
self.product_data,
)
product = Product.objects.get(prefix=self.product_data['prefix'])
serializer = ProductSerializer(product)

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, serializer.data)

def test_update_product_bad_data(self):
response = self.client.put(
reverse('product-detail', args=[self.bob.prefix]),
self.bad_product_data,
)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

def test_delete_product(self):
response = self.client.delete(
reverse('product-detail', args=[self.ally.prefix]),
)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
@@ -0,0 +1,38 @@
# 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 path
from django.conf.urls import include
from rest_framework import routers
from . import views

router = routers.DefaultRouter()
router.register('users', views.UserViewSet)
router.register('groups', views.GroupViewSet)
router.register('products', views.ProductViewSet)
router.register('tickets', views.TicketViewSet)

ticket_router = routers.DefaultRouter()
ticket_router.register('ticketevents', views.ChangeEventViewSet)

urlpatterns = [
path('', include(router.urls)),
path('tickets/<uuid:id>/', include(ticket_router.urls)),
path('swagger<str:format>', views.schema_view.without_ui(cache_timeout=0), name='schema-json'),
path('swagger/', views.schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
path('redoc/', views.schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]
@@ -0,0 +1,64 @@
# 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.contrib.auth.models import User, Group
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from rest_framework import permissions, viewsets
from . import serializers
from ..models import Product
from trackers import models


schema_view = get_schema_view(
openapi.Info(
title='Bloodhound Core API',
default_version='v1',
),
public=True,
permission_classes=(permissions.AllowAny,),
)


class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = serializers.UserSerializer


class GroupViewSet(viewsets.ModelViewSet):
queryset = Group.objects.all()
serializer_class = serializers.GroupSerializer


class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = serializers.ProductSerializer


class TicketFieldViewSet(viewsets.ModelViewSet):
queryset = models.TicketField.objects.all()
serializer_class = serializers.TicketFieldSerializer


class TicketViewSet(viewsets.ModelViewSet):
queryset = models.Ticket.objects.all()
serializer_class = serializers.TicketSerializer


class ChangeEventViewSet(viewsets.ModelViewSet):
queryset = models.ChangeEvent.objects.all()
serializer_class = serializers.ChangeEventSerializer
@@ -19,4 +19,5 @@


class TrackersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'trackers'
@@ -26,6 +26,38 @@
logger = logging.getLogger(__name__)


class Product(models.Model):
prefix = models.TextField(primary_key=True)
name = models.TextField()
description = models.TextField(blank=True, null=True)
owner = models.TextField(blank=True, null=True)

class Meta:
db_table = 'bloodhound_product'


class ProductConfig(models.Model):
"""Possibly legacy table - keeping for now"""
product = models.ForeignKey(Product, on_delete=models.CASCADE)
section = models.TextField()
option = models.TextField()
value = models.TextField(blank=True, null=True)

class Meta:
db_table = 'bloodhound_productconfig'
unique_together = (('product', 'section', 'option'),)


class ProductResourceMap(models.Model):
"""Possibly legacy model - keeping for now"""
product_id = models.ForeignKey(Product, on_delete=models.CASCADE)
resource_type = models.TextField(blank=True, null=True)
resource_id = models.TextField(blank=True, null=True)

class Meta:
db_table = 'bloodhound_productresourcemap'


class ModelCommon(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False)
Empty file.

0 comments on commit dc439b7

Please sign in to comment.