From 38ed612cb9a9fa3712ea9cf6025a38a3ac5a8f20 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 22 Sep 2020 13:50:55 -0400 Subject: [PATCH] Add test for API bulk updates --- netbox/circuits/tests/test_api.py | 9 +++ netbox/dcim/tests/test_api.py | 91 +++++++++++++++++++++++++ netbox/extras/tests/test_api.py | 9 +++ netbox/ipam/tests/test_api.py | 27 ++++++++ netbox/tenancy/tests/test_api.py | 6 ++ netbox/utilities/testing/api.py | 27 ++++++++ netbox/virtualization/tests/test_api.py | 12 ++++ 7 files changed, 181 insertions(+) diff --git a/netbox/circuits/tests/test_api.py b/netbox/circuits/tests/test_api.py index 8a6289401..48493d5ef 100644 --- a/netbox/circuits/tests/test_api.py +++ b/netbox/circuits/tests/test_api.py @@ -32,6 +32,9 @@ class ProviderTest(APIViewTestCases.APIViewTestCase): 'slug': 'provider-6', }, ] + bulk_update_data = { + 'asn': 1234, + } @classmethod def setUpTestData(cls): @@ -61,6 +64,9 @@ class CircuitTypeTest(APIViewTestCases.APIViewTestCase): 'slug': 'circuit-type-6', }, ) + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -76,6 +82,9 @@ class CircuitTypeTest(APIViewTestCases.APIViewTestCase): class CircuitTest(APIViewTestCases.APIViewTestCase): model = Circuit brief_fields = ['cid', 'id', 'url'] + bulk_update_data = { + 'status': 'planned', + } @classmethod def setUpTestData(cls): diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 286405e54..512d7919c 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -80,6 +80,9 @@ class RegionTest(APIViewTestCases.APIViewTestCase): 'slug': 'region-6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -92,6 +95,9 @@ class RegionTest(APIViewTestCases.APIViewTestCase): class SiteTest(APIViewTestCases.APIViewTestCase): model = Site brief_fields = ['id', 'name', 'slug', 'url'] + bulk_update_data = { + 'status': 'planned', + } @classmethod def setUpTestData(cls): @@ -133,6 +139,9 @@ class SiteTest(APIViewTestCases.APIViewTestCase): class RackGroupTest(APIViewTestCases.APIViewTestCase): model = RackGroup brief_fields = ['_depth', 'id', 'name', 'rack_count', 'slug', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -194,6 +203,9 @@ class RackRoleTest(APIViewTestCases.APIViewTestCase): 'color': 'ffff00', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -209,6 +221,9 @@ class RackRoleTest(APIViewTestCases.APIViewTestCase): class RackTest(APIViewTestCases.APIViewTestCase): model = Rack brief_fields = ['device_count', 'display_name', 'id', 'name', 'url'] + bulk_update_data = { + 'status': 'planned', + } @classmethod def setUpTestData(cls): @@ -294,6 +309,9 @@ class RackTest(APIViewTestCases.APIViewTestCase): class RackReservationTest(APIViewTestCases.APIViewTestCase): model = RackReservation brief_fields = ['id', 'units', 'url', 'user'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -356,6 +374,9 @@ class ManufacturerTest(APIViewTestCases.APIViewTestCase): 'slug': 'manufacturer-6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -371,6 +392,9 @@ class ManufacturerTest(APIViewTestCases.APIViewTestCase): class DeviceTypeTest(APIViewTestCases.APIViewTestCase): model = DeviceType brief_fields = ['device_count', 'display_name', 'id', 'manufacturer', 'model', 'slug', 'url'] + bulk_update_data = { + 'part_number': 'ABC123', + } @classmethod def setUpTestData(cls): @@ -410,6 +434,9 @@ class DeviceTypeTest(APIViewTestCases.APIViewTestCase): class ConsolePortTemplateTest(APIViewTestCases.APIViewTestCase): model = ConsolePortTemplate brief_fields = ['id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -444,6 +471,9 @@ class ConsolePortTemplateTest(APIViewTestCases.APIViewTestCase): class ConsoleServerPortTemplateTest(APIViewTestCases.APIViewTestCase): model = ConsoleServerPortTemplate brief_fields = ['id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -478,6 +508,9 @@ class ConsoleServerPortTemplateTest(APIViewTestCases.APIViewTestCase): class PowerPortTemplateTest(APIViewTestCases.APIViewTestCase): model = PowerPortTemplate brief_fields = ['id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -512,6 +545,9 @@ class PowerPortTemplateTest(APIViewTestCases.APIViewTestCase): class PowerOutletTemplateTest(APIViewTestCases.APIViewTestCase): model = PowerOutletTemplate brief_fields = ['id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -546,6 +582,9 @@ class PowerOutletTemplateTest(APIViewTestCases.APIViewTestCase): class InterfaceTemplateTest(APIViewTestCases.APIViewTestCase): model = InterfaceTemplate brief_fields = ['id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -583,6 +622,9 @@ class InterfaceTemplateTest(APIViewTestCases.APIViewTestCase): class FrontPortTemplateTest(APIViewTestCases.APIViewTestCase): model = FrontPortTemplate brief_fields = ['id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -651,6 +693,9 @@ class FrontPortTemplateTest(APIViewTestCases.APIViewTestCase): class RearPortTemplateTest(APIViewTestCases.APIViewTestCase): model = RearPortTemplate brief_fields = ['id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -688,6 +733,9 @@ class RearPortTemplateTest(APIViewTestCases.APIViewTestCase): class DeviceBayTemplateTest(APIViewTestCases.APIViewTestCase): model = DeviceBayTemplate brief_fields = ['id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -739,6 +787,9 @@ class DeviceRoleTest(APIViewTestCases.APIViewTestCase): 'color': 'ffff00', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -768,6 +819,9 @@ class PlatformTest(APIViewTestCases.APIViewTestCase): 'slug': 'platform-6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -783,6 +837,9 @@ class PlatformTest(APIViewTestCases.APIViewTestCase): class DeviceTest(APIViewTestCases.APIViewTestCase): model = Device brief_fields = ['display_name', 'id', 'name', 'url'] + bulk_update_data = { + 'status': 'failed', + } @classmethod def setUpTestData(cls): @@ -921,6 +978,9 @@ class DeviceTest(APIViewTestCases.APIViewTestCase): class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = ConsolePort brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } peer_termination_type = ConsoleServerPort @classmethod @@ -957,6 +1017,9 @@ class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = ConsoleServerPort brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } peer_termination_type = ConsolePort @classmethod @@ -993,6 +1056,9 @@ class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIView class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = PowerPort brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } peer_termination_type = PowerOutlet @classmethod @@ -1029,6 +1095,9 @@ class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = PowerOutlet brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } peer_termination_type = PowerPort @classmethod @@ -1065,6 +1134,9 @@ class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = Interface brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } peer_termination_type = Interface @classmethod @@ -1120,6 +1192,9 @@ class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase class FrontPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = FrontPort brief_fields = ['cable', 'device', 'id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } peer_termination_type = Interface @classmethod @@ -1175,6 +1250,9 @@ class FrontPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase class RearPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = RearPort brief_fields = ['cable', 'device', 'id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } peer_termination_type = Interface @classmethod @@ -1214,6 +1292,9 @@ class RearPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase) class DeviceBayTest(APIViewTestCases.APIViewTestCase): model = DeviceBay brief_fields = ['device', 'id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -1274,6 +1355,9 @@ class DeviceBayTest(APIViewTestCases.APIViewTestCase): class InventoryItemTest(APIViewTestCases.APIViewTestCase): model = InventoryItem brief_fields = ['_depth', 'device', 'id', 'name', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -1309,6 +1393,10 @@ class InventoryItemTest(APIViewTestCases.APIViewTestCase): class CableTest(APIViewTestCases.APIViewTestCase): model = Cable brief_fields = ['id', 'label', 'url'] + bulk_update_data = { + 'length': 100, + 'length_unit': 'm', + } # TODO: Allow updating cable terminations test_update_object = None @@ -1894,6 +1982,9 @@ class PowerPanelTest(APIViewTestCases.APIViewTestCase): class PowerFeedTest(APIViewTestCases.APIViewTestCase): model = PowerFeed brief_fields = ['cable', 'id', 'name', 'url'] + bulk_update_data = { + 'status': 'planned', + } @classmethod def setUpTestData(cls): diff --git a/netbox/extras/tests/test_api.py b/netbox/extras/tests/test_api.py index f66fea2ac..860aed56f 100644 --- a/netbox/extras/tests/test_api.py +++ b/netbox/extras/tests/test_api.py @@ -49,6 +49,9 @@ class ExportTemplateTest(APIViewTestCases.APIViewTestCase): 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -91,6 +94,9 @@ class TagTest(APIViewTestCases.APIViewTestCase): 'slug': 'tag-6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -164,6 +170,9 @@ class ConfigContextTest(APIViewTestCases.APIViewTestCase): 'data': {'more_baz': None}, }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): diff --git a/netbox/ipam/tests/test_api.py b/netbox/ipam/tests/test_api.py index 4f514aab0..2cc24b6ae 100644 --- a/netbox/ipam/tests/test_api.py +++ b/netbox/ipam/tests/test_api.py @@ -37,6 +37,9 @@ class VRFTest(APIViewTestCases.APIViewTestCase): 'rd': '65000:6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -66,6 +69,9 @@ class RIRTest(APIViewTestCases.APIViewTestCase): 'slug': 'rir-6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -81,6 +87,9 @@ class RIRTest(APIViewTestCases.APIViewTestCase): class AggregateTest(APIViewTestCases.APIViewTestCase): model = Aggregate brief_fields = ['family', 'id', 'prefix', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -131,6 +140,9 @@ class RoleTest(APIViewTestCases.APIViewTestCase): 'slug': 'role-6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -157,6 +169,9 @@ class PrefixTest(APIViewTestCases.APIViewTestCase): 'prefix': '192.168.6.0/24', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -328,6 +343,9 @@ class IPAddressTest(APIViewTestCases.APIViewTestCase): 'address': '192.168.0.6/24', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -357,6 +375,9 @@ class VLANGroupTest(APIViewTestCases.APIViewTestCase): 'slug': 'vlan-group-6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -372,6 +393,9 @@ class VLANGroupTest(APIViewTestCases.APIViewTestCase): class VLANTest(APIViewTestCases.APIViewTestCase): model = VLAN brief_fields = ['display_name', 'id', 'name', 'url', 'vid'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -429,6 +453,9 @@ class VLANTest(APIViewTestCases.APIViewTestCase): class ServiceTest(APIViewTestCases.APIViewTestCase): model = Service brief_fields = ['id', 'name', 'ports', 'protocol', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): diff --git a/netbox/tenancy/tests/test_api.py b/netbox/tenancy/tests/test_api.py index f04b2a7ce..7af3c8d79 100644 --- a/netbox/tenancy/tests/test_api.py +++ b/netbox/tenancy/tests/test_api.py @@ -17,6 +17,9 @@ class AppTest(APITestCase): class TenantGroupTest(APIViewTestCases.APIViewTestCase): model = TenantGroup brief_fields = ['_depth', 'id', 'name', 'slug', 'tenant_count', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -52,6 +55,9 @@ class TenantGroupTest(APIViewTestCases.APIViewTestCase): class TenantTest(APIViewTestCases.APIViewTestCase): model = Tenant brief_fields = ['id', 'name', 'slug', 'url'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): diff --git a/netbox/utilities/testing/api.py b/netbox/utilities/testing/api.py index 2c6c70fea..222e3bdce 100644 --- a/netbox/utilities/testing/api.py +++ b/netbox/utilities/testing/api.py @@ -234,6 +234,7 @@ class APIViewTestCases: class UpdateObjectViewTestCase(APITestCase): update_data = {} + bulk_update_data = None def test_update_object_without_permission(self): """ @@ -268,6 +269,32 @@ class APIViewTestCases: instance.refresh_from_db() self.assertInstanceEqual(instance, self.update_data, api=True) + def test_bulk_update_objects(self): + """ + PATCH a set of objects in a single request. + """ + if self.bulk_update_data is None: + self.skipTest("Bulk update data not set") + + # Add object-level permission + obj_perm = ObjectPermission( + actions=['change'] + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ContentType.objects.get_for_model(self.model)) + + id_list = self._get_queryset().values_list('id', flat=True)[:3] + self.assertEqual(len(id_list), 3, "Insufficient number of objects to test bulk update") + data = [ + {'id': id, **self.bulk_update_data} for id in id_list + ] + + response = self.client.patch(self._get_list_url(), data, format='json', **self.header) + self.assertHttpStatus(response, status.HTTP_200_OK) + for instance in self._get_queryset().filter(pk__in=id_list): + self.assertInstanceEqual(instance, self.bulk_update_data, api=True) + class DeleteObjectViewTestCase(APITestCase): def test_delete_object_without_permission(self): diff --git a/netbox/virtualization/tests/test_api.py b/netbox/virtualization/tests/test_api.py index 28d4bbb99..d0e3fccfa 100644 --- a/netbox/virtualization/tests/test_api.py +++ b/netbox/virtualization/tests/test_api.py @@ -34,6 +34,9 @@ class ClusterTypeTest(APIViewTestCases.APIViewTestCase): 'slug': 'cluster-type-6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -63,6 +66,9 @@ class ClusterGroupTest(APIViewTestCases.APIViewTestCase): 'slug': 'cluster-type-6', }, ] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls): @@ -123,6 +129,9 @@ class ClusterTest(APIViewTestCases.APIViewTestCase): class VirtualMachineTest(APIViewTestCases.APIViewTestCase): model = VirtualMachine brief_fields = ['id', 'name', 'url'] + bulk_update_data = { + 'status': 'staged', + } @classmethod def setUpTestData(cls): @@ -196,6 +205,9 @@ class VirtualMachineTest(APIViewTestCases.APIViewTestCase): class VMInterfaceTest(APIViewTestCases.APIViewTestCase): model = VMInterface brief_fields = ['id', 'name', 'url', 'virtual_machine'] + bulk_update_data = { + 'description': 'New description', + } @classmethod def setUpTestData(cls):