|
|
@@ -24,8 +24,10 @@ from netbox.choices import DiameterUnitChoices, FlowRateUnitChoices, WeightUnitC
|
|
|
from netbox.context_managers import event_tracking
|
|
|
from tenancy.models import Tenant
|
|
|
from users.models import User
|
|
|
+from utilities.conversion import to_grams
|
|
|
from utilities.data import drange
|
|
|
from utilities.testing import create_test_device, create_test_image
|
|
|
+from utilities.testing.mixins import NormalizedMeasurementTestMixin
|
|
|
from virtualization.models import Cluster, ClusterType
|
|
|
|
|
|
|
|
|
@@ -225,6 +227,28 @@ class DeviceTypeTestCase(TestCase):
|
|
|
self.assertEqual(device_type.interface_template_count, 1)
|
|
|
|
|
|
|
|
|
+class DeviceTypeWeightTestCase(NormalizedMeasurementTestMixin, TestCase):
|
|
|
+ model = DeviceType
|
|
|
+ value_field = 'weight'
|
|
|
+ unit_field = 'weight_unit'
|
|
|
+ normalized_field = '_abs_weight'
|
|
|
+ unit_choices = WeightUnitChoices
|
|
|
+ converter = staticmethod(to_grams)
|
|
|
+
|
|
|
+ @classmethod
|
|
|
+ def setUpTestData(cls):
|
|
|
+ cls.manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
|
|
|
+
|
|
|
+ def create_instance(self, **attrs):
|
|
|
+ index = next(self.sequence)
|
|
|
+ return DeviceType(
|
|
|
+ manufacturer=self.manufacturer,
|
|
|
+ model=f'Device Type {index}',
|
|
|
+ slug=f'device-type-{index}',
|
|
|
+ **attrs
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
class DeviceTypeImageTestCase(TestCase):
|
|
|
"""
|
|
|
Test the handling of DeviceType front/rear image files.
|
|
|
@@ -581,6 +605,24 @@ class RackTypeTestCase(TestCase):
|
|
|
self.assertEqual(rack.cooling_capacity, rack_type.cooling_capacity)
|
|
|
|
|
|
|
|
|
+class RackMaxWeightTestCase(NormalizedMeasurementTestMixin, TestCase):
|
|
|
+ model = Rack
|
|
|
+ value_field = 'max_weight'
|
|
|
+ unit_field = 'weight_unit'
|
|
|
+ normalized_field = '_abs_max_weight'
|
|
|
+ unit_choices = WeightUnitChoices
|
|
|
+ converter = staticmethod(to_grams)
|
|
|
+ # The largest value the integer column holds; multiplying it as an integer would overflow
|
|
|
+ value = 2147483647
|
|
|
+
|
|
|
+ @classmethod
|
|
|
+ def setUpTestData(cls):
|
|
|
+ cls.site = Site.objects.create(name='Site 1', slug='site-1')
|
|
|
+
|
|
|
+ def create_instance(self, **attrs):
|
|
|
+ return Rack(site=self.site, name=f'Rack {next(self.sequence)}', **attrs)
|
|
|
+
|
|
|
+
|
|
|
class RackTestCase(TestCase):
|
|
|
|
|
|
@classmethod
|
|
|
@@ -4681,3 +4723,40 @@ class CoolingComponentTestCase(TestCase):
|
|
|
cooling_outflow.cooling_intake = cooling_intake
|
|
|
with self.assertRaises(ValidationError):
|
|
|
cooling_outflow.full_clean()
|
|
|
+
|
|
|
+ def test_instantiate_clears_unit_without_value(self):
|
|
|
+ """
|
|
|
+ bulk_create() bypasses save(), so instantiate() must itself clear a unit whose value is unset.
|
|
|
+ """
|
|
|
+ device_type = DeviceType.objects.create(
|
|
|
+ manufacturer=self.manufacturer, model='Device Type 8', slug='device-type-8'
|
|
|
+ )
|
|
|
+ intake_template = CoolingIntakeTemplate.objects.create(
|
|
|
+ device_type=device_type,
|
|
|
+ name='Cooling Port 1',
|
|
|
+ diameter=Decimal('10'),
|
|
|
+ diameter_unit=DiameterUnitChoices.UNIT_MILLIMETER,
|
|
|
+ max_flow=Decimal('5'),
|
|
|
+ max_flow_unit=FlowRateUnitChoices.UNIT_LITERS_PER_MINUTE,
|
|
|
+ )
|
|
|
+ outflow_template = CoolingOutflowTemplate.objects.create(
|
|
|
+ device_type=device_type,
|
|
|
+ name='Cooling Outlet 1',
|
|
|
+ diameter=Decimal('10'),
|
|
|
+ diameter_unit=DiameterUnitChoices.UNIT_MILLIMETER,
|
|
|
+ )
|
|
|
+ # Leave the units dangling without passing through save()
|
|
|
+ CoolingIntakeTemplate.objects.filter(pk=intake_template.pk).update(diameter=None, max_flow=None)
|
|
|
+ CoolingOutflowTemplate.objects.filter(pk=outflow_template.pk).update(diameter=None)
|
|
|
+
|
|
|
+ device = Device.objects.create(
|
|
|
+ site=self.site, device_type=device_type, role=self.role, name='Device F'
|
|
|
+ )
|
|
|
+ cooling_intake = CoolingIntake.objects.get(device=device, name='Cooling Port 1')
|
|
|
+ self.assertIsNone(cooling_intake.diameter)
|
|
|
+ self.assertIsNone(cooling_intake.diameter_unit)
|
|
|
+ self.assertIsNone(cooling_intake.max_flow)
|
|
|
+ self.assertIsNone(cooling_intake.max_flow_unit)
|
|
|
+ cooling_outflow = CoolingOutflow.objects.get(device=device, name='Cooling Outlet 1')
|
|
|
+ self.assertIsNone(cooling_outflow.diameter)
|
|
|
+ self.assertIsNone(cooling_outflow.diameter_unit)
|