12826 add tests and fixes

This commit is contained in:
Arthur Hanson 2024-06-25 11:11:37 -07:00
parent fc1ce31b00
commit 811c1bdfaa
11 changed files with 360 additions and 43 deletions

View File

@ -3,7 +3,7 @@ from rest_framework import serializers
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from dcim.models import Rack, RackReservation, RackRole from dcim.models import Rack, RackReservation, RackRole, RackType
from netbox.api.fields import ChoiceField, RelatedObjectCountField from netbox.api.fields import ChoiceField, RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NetBoxModelSerializer
from netbox.config import ConfigItem from netbox.config import ConfigItem
@ -41,7 +41,7 @@ class RackTypeSerializer(NetBoxModelSerializer):
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True) weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
class Meta: class Meta:
model = Rack model = RackType
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'id', 'url', 'display_url', 'display', 'name',
'type', 'width', 'u_height', 'starting_unit', 'weight', 'max_weight', 'type', 'width', 'u_height', 'starting_unit', 'weight', 'max_weight',

View File

@ -297,19 +297,9 @@ class RackTypeFilterSet(NetBoxModelFilterSet):
width = django_filters.MultipleChoiceFilter( width = django_filters.MultipleChoiceFilter(
choices=RackWidthChoices choices=RackWidthChoices
) )
role_id = django_filters.ModelMultipleChoiceFilter(
queryset=RackRole.objects.all(),
label=_('Role (ID)'),
)
role = django_filters.ModelMultipleChoiceFilter(
field_name='role__slug',
queryset=RackRole.objects.all(),
to_field_name='slug',
label=_('Role (slug)'),
)
class Meta: class Meta:
model = Rack model = RackType
fields = ( fields = (
'id', 'name', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'id', 'name', 'u_height', 'starting_unit', 'desc_units', 'outer_width',
'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description',

View File

@ -241,11 +241,10 @@ class RackRoleFilterForm(NetBoxModelFilterSetForm):
class RackTypeFilterForm(NetBoxModelFilterSetForm): class RackTypeFilterForm(NetBoxModelFilterSetForm):
model = Rack model = RackType
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
FieldSet('role_id', name=_('Function')), FieldSet('type', 'width', name=_('Hardware')),
FieldSet('type', 'width', 'serial', name=_('Hardware')),
FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')), FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
) )
selector_fields = ('filter_id', 'q',) selector_fields = ('filter_id', 'q',)
@ -259,16 +258,6 @@ class RackTypeFilterForm(NetBoxModelFilterSetForm):
choices=RackWidthChoices, choices=RackWidthChoices,
required=False required=False
) )
role_id = DynamicModelMultipleChoiceField(
queryset=RackRole.objects.all(),
required=False,
null_option='None',
label=_('Role')
)
serial = forms.CharField(
label=_('Serial'),
required=False
)
tag = TagFilterField(model) tag = TagFilterField(model)
weight = forms.DecimalField( weight = forms.DecimalField(
label=_('Weight'), label=_('Weight'),

View File

@ -120,7 +120,7 @@ class RackType(ImageAttachmentsMixin, PrimaryModel, WeightMixin):
) )
clone_fields = ( clone_fields = (
'role', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'type', 'width', 'u_height', 'desc_units', 'outer_width',
'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit',
) )
prerequisite_models = ( prerequisite_models = (
@ -172,21 +172,6 @@ class RackType(ImageAttachmentsMixin, PrimaryModel, WeightMixin):
return drange(decimal.Decimal(self.starting_unit), self.u_height + self.starting_unit, 0.5) return drange(decimal.Decimal(self.starting_unit), self.u_height + self.starting_unit, 0.5)
return drange(self.u_height + decimal.Decimal(0.5) + self.starting_unit - 1, 0.5 + self.starting_unit - 1, -0.5) return drange(self.u_height + decimal.Decimal(0.5) + self.starting_unit - 1, 0.5 + self.starting_unit - 1, -0.5)
@cached_property
def total_weight(self):
total_weight = sum(
device.device_type._abs_weight
for device in self.devices.exclude(device_type___abs_weight__isnull=True).prefetch_related('device_type')
)
total_weight += sum(
module.module_type._abs_weight
for module in Module.objects.filter(device__rack=self)
.exclude(module_type___abs_weight__isnull=True)
.prefetch_related('module_type')
)
if self._abs_weight:
total_weight += self._abs_weight
return round(total_weight / 1000, 2)
# #
# Racks # Racks

View File

@ -242,6 +242,19 @@ class PowerPortIndex(SearchIndex):
display_attrs = ('device', 'label', 'type', 'description') display_attrs = ('device', 'label', 'type', 'description')
@register_search
class RackTypeIndex(SearchIndex):
model = models.RackType
fields = (
('name', 100),
('description', 500),
('comments', 5000),
)
display_attrs = (
'site', 'description',
)
@register_search @register_search
class RackIndex(SearchIndex): class RackIndex(SearchIndex):
model = models.Rack model = models.Rack

View File

@ -274,6 +274,36 @@ class RackRoleTest(APIViewTestCases.APIViewTestCase):
RackRole.objects.bulk_create(rack_roles) RackRole.objects.bulk_create(rack_roles)
class RackTypeTest(APIViewTestCases.APIViewTestCase):
model = RackType
brief_fields = ['description', 'display', 'id', 'name', 'url']
bulk_update_data = {
'description': 'new description',
}
@classmethod
def setUpTestData(cls):
racks = (
RackType(name='Rack 1'),
RackType(name='Rack 2'),
RackType(name='Rack 3'),
)
RackType.objects.bulk_create(racks)
cls.create_data = [
{
'name': 'Test Rack 4',
},
{
'name': 'Test Rack 5',
},
{
'name': 'Test Rack 6',
},
]
class RackTest(APIViewTestCases.APIViewTestCase): class RackTest(APIViewTestCases.APIViewTestCase):
model = Rack model = Rack
brief_fields = ['description', 'device_count', 'display', 'id', 'name', 'url'] brief_fields = ['description', 'device_count', 'display', 'id', 'name', 'url']

View File

@ -468,6 +468,121 @@ class RackRoleTestCase(TestCase, ChangeLoggedFilterSetTests):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = RackType.objects.all()
filterset = RackTypeFilterSet
@classmethod
def setUpTestData(cls):
racks = (
RackType(
name='Rack 1',
type=RackTypeChoices.TYPE_2POST,
width=RackWidthChoices.WIDTH_19IN,
u_height=42,
desc_units=False,
outer_width=100,
outer_depth=100,
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
weight=10,
max_weight=1000,
weight_unit=WeightUnitChoices.UNIT_POUND,
description='foobar1'
),
RackType(
name='Rack 2',
type=RackTypeChoices.TYPE_4POST,
width=RackWidthChoices.WIDTH_21IN,
u_height=43,
desc_units=False,
outer_width=200,
outer_depth=200,
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
weight=20,
max_weight=2000,
weight_unit=WeightUnitChoices.UNIT_POUND,
description='foobar2'
),
RackType(
name='Rack 3',
type=RackTypeChoices.TYPE_CABINET,
width=RackWidthChoices.WIDTH_23IN,
u_height=44,
desc_units=True,
outer_width=300,
outer_depth=300,
outer_unit=RackDimensionUnitChoices.UNIT_INCH,
weight=30,
max_weight=3000,
weight_unit=WeightUnitChoices.UNIT_KILOGRAM,
description='foobar3'
),
)
RackType.objects.bulk_create(racks)
def test_q(self):
params = {'q': 'foobar1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_name(self):
params = {'name': ['Rack 1', 'Rack 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_description(self):
params = {'description': ['foobar1', 'foobar2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_type(self):
params = {'type': [RackTypeChoices.TYPE_2POST, RackTypeChoices.TYPE_4POST]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_width(self):
params = {'width': [RackWidthChoices.WIDTH_19IN, RackWidthChoices.WIDTH_21IN]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_u_height(self):
params = {'u_height': [42, 43]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_starting_unit(self):
params = {'starting_unit': [1]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
params = {'starting_unit': [2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
def test_desc_units(self):
params = {'desc_units': 'true'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
params = {'desc_units': 'false'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_outer_width(self):
params = {'outer_width': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_outer_depth(self):
params = {'outer_depth': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_outer_unit(self):
self.assertEqual(Rack.objects.filter(outer_unit__isnull=False).count(), 3)
params = {'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_weight(self):
params = {'weight': [10, 20]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_max_weight(self):
params = {'max_weight': [1000, 2000]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_weight_unit(self):
params = {'weight_unit': WeightUnitChoices.UNIT_POUND}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class RackTestCase(TestCase, ChangeLoggedFilterSetTests): class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Rack.objects.all() queryset = Rack.objects.all()
filterset = RackFilterSet filterset = RackFilterSet

View File

@ -74,6 +74,17 @@ class LocationTestCase(TestCase):
self.assertEqual(PowerPanel.objects.get(pk=powerpanel1.pk).site, site_b) self.assertEqual(PowerPanel.objects.get(pk=powerpanel1.pk).site, site_b)
class RackTypeTestCase(TestCase):
@classmethod
def setUpTestData(cls):
RackType.objects.create(
name='Rack 1',
u_height=42
)
class RackTestCase(TestCase): class RackTestCase(TestCase):
@classmethod @classmethod

View File

@ -336,6 +336,67 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
} }
class RackTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = RackType
@classmethod
def setUpTestData(cls):
racks = (
Rack(name='Rack 1'),
Rack(name='Rack 2'),
Rack(name='Rack 3'),
)
RackType.objects.bulk_create(racks)
tags = create_tags('Alpha', 'Bravo', 'Charlie')
cls.form_data = {
'name': 'Rack X',
'type': RackTypeChoices.TYPE_CABINET,
'width': RackWidthChoices.WIDTH_19IN,
'u_height': 48,
'desc_units': False,
'outer_width': 500,
'outer_depth': 500,
'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER,
'starting_unit': 1,
'weight': 100,
'max_weight': 2000,
'weight_unit': WeightUnitChoices.UNIT_POUND,
'comments': 'Some comments',
'tags': [t.pk for t in tags],
}
cls.csv_data = (
"name,width,u_height,weight,max_weight,weight_unit",
",Rack 4,19,42,100,2000,kg",
"Rack 5,19,42,100,2000,kg",
"Rack 6,19,42,100,2000,kg",
)
cls.csv_update_data = (
"id,name",
f"{racks[0].pk},Rack 7",
f"{racks[1].pk},Rack 8",
f"{racks[2].pk},Rack 9",
)
cls.bulk_edit_data = {
'type': RackTypeChoices.TYPE_4POST,
'width': RackWidthChoices.WIDTH_23IN,
'u_height': 49,
'desc_units': True,
'outer_width': 30,
'outer_depth': 30,
'outer_unit': RackDimensionUnitChoices.UNIT_INCH,
'weight': 200,
'max_weight': 4000,
'weight_unit': WeightUnitChoices.UNIT_POUND,
'comments': 'New comments',
}
class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase): class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Rack model = Rack

View File

@ -592,7 +592,7 @@ class RackTypeListView(generic.ObjectListView):
@register_model_view(RackType) @register_model_view(RackType)
class RackTypeView(GetRelatedModelsMixin, generic.ObjectView): class RackTypeView(GetRelatedModelsMixin, generic.ObjectView):
queryset = Rack.objects.prefetch_related('role') queryset = RackType.objects.all()
@register_model_view(RackType, 'edit') @register_model_view(RackType, 'edit')

View File

@ -0,0 +1,123 @@
{% extends 'dcim/rack/base.html' %}
{% load buttons %}
{% load helpers %}
{% load static %}
{% load plugins %}
{% load i18n %}
{% load mptt %}
{% block content %}
<div class="row">
<div class="col col-12 col-xl-5">
<div class="card">
<h5 class="card-header">{% trans "Rack" %}</h5>
<table class="table table-hover attr-table">
<tr>
<th scope="row">{% trans "Description" %}</th>
<td>{{ object.description|placeholder }}</td>
</tr>
</table>
</div>
<div class="card">
<h5 class="card-header">{% trans "Dimensions" %}</h5>
<table class="table table-hover attr-table">
<tr>
<th scope="row">{% trans "Type" %}</th>
<td>
{% if object.type %}
{{ object.get_type_display }}
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
</tr>
<tr>
<th scope="row">{% trans "Width" %}</th>
<td>{{ object.get_width_display }}</td>
</tr>
<tr>
<th scope="row">{% trans "Height" %}</th>
<td>{{ object.u_height }}U ({% if object.desc_units %}{% trans "descending" %}{% else %}{% trans "ascending" %}{% endif %})</td>
</tr>
<tr>
<th scope="row">{% trans "Starting Unit" %}</th>
<td>
{{ object.starting_unit }}
</td>
</tr>
<tr>
<th scope="row">{% trans "Outer Width" %}</th>
<td>
{% if object.outer_width %}
{{ object.outer_width }} {{ object.get_outer_unit_display }}
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
</tr>
<tr>
<th scope="row">{% trans "Outer Depth" %}</th>
<td>
{% if object.outer_depth %}
{{ object.outer_depth }} {{ object.get_outer_unit_display }}
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
</tr>
<tr>
<th scope="row">{% trans "Mounting Depth" %}</th>
<td>
{% if object.mounting_depth %}
{{ object.mounting_depth }} {% trans "Millimeters" %}
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
</tr>
<tr>
<th scope="row">{% trans "Rack Weight" %}</th>
<td>
{% if object.weight %}
{{ object.weight|floatformat }} {{ object.get_weight_unit_display }}
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
</tr>
<tr>
<th scope="row">{% trans "Maximum Weight" %}</th>
<td>
{% if object.max_weight %}
{{ object.max_weight }} {{ object.get_weight_unit_display }}
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
</tr>
</table>
</div>
{% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/comments.html' %}
{% include 'inc/panels/image_attachments.html' %}
{% plugin_left_page object %}
</div>
<div class="col col-12 col-xl-7">
<div class="text-end mb-4">
<select class="btn btn-outline-secondary no-ts rack-view">
<option value="images-and-labels" selected="selected">{% trans "Images and Labels" %}</option>
<option value="images-only">{% trans "Images only" %}</option>
<option value="labels-only">{% trans "Labels only" %}</option>
</select>
</div>
{% include 'inc/panels/related_objects.html' %}
{% plugin_right_page object %}
</div>
</div>
<div class="row">
<div class="col col-md-12">
{% plugin_full_width_page object %}
</div>
</div>
{% endblock %}