diff --git a/netbox/extras/tests/test_changelog.py b/netbox/extras/tests/test_changelog.py index c15bc2a11..9786ae2cc 100644 --- a/netbox/extras/tests/test_changelog.py +++ b/netbox/extras/tests/test_changelog.py @@ -40,8 +40,8 @@ class ChangeLogViewTest(ModelViewTestCase): def test_create_object(self): tags = self.create_tags('Tag 1', 'Tag 2') form_data = { - 'name': 'Test Site 1', - 'slug': 'test-site-1', + 'name': 'Site 1', + 'slug': 'site-1', 'status': SiteStatusChoices.STATUS_ACTIVE, 'cf_my_field': 'ABC', 'cf_my_field_select': 'Bar', @@ -56,7 +56,7 @@ class ChangeLogViewTest(ModelViewTestCase): response = self.client.post(**request) self.assertHttpStatus(response, 302) - site = Site.objects.get(name='Test Site 1') + site = Site.objects.get(name='Site 1') # First OC is the creation; second is the tags update oc_list = ObjectChange.objects.filter( changed_object_type=ContentType.objects.get_for_model(Site), @@ -71,14 +71,14 @@ class ChangeLogViewTest(ModelViewTestCase): self.assertEqual(oc_list[1].postchange_data['tags'], ['Tag 1', 'Tag 2']) def test_update_object(self): - site = Site(name='Test Site 1', slug='test-site-1') + site = Site(name='Site 1', slug='site-1') site.save() tags = self.create_tags('Tag 1', 'Tag 2', 'Tag 3') site.tags.set('Tag 1', 'Tag 2') form_data = { - 'name': 'Test Site X', - 'slug': 'test-site-x', + 'name': 'Site X', + 'slug': 'site-x', 'status': SiteStatusChoices.STATUS_PLANNED, 'cf_my_field': 'DEF', 'cf_my_field_select': 'Foo', @@ -101,7 +101,7 @@ class ChangeLogViewTest(ModelViewTestCase): ).first() self.assertEqual(oc.changed_object, site) self.assertEqual(oc.action, ObjectChangeActionChoices.ACTION_UPDATE) - self.assertEqual(oc.prechange_data['name'], 'Test Site 1') + self.assertEqual(oc.prechange_data['name'], 'Site 1') self.assertEqual(oc.prechange_data['tags'], ['Tag 1', 'Tag 2']) self.assertEqual(oc.postchange_data['custom_fields']['my_field'], form_data['cf_my_field']) self.assertEqual(oc.postchange_data['custom_fields']['my_field_select'], form_data['cf_my_field_select']) @@ -109,8 +109,8 @@ class ChangeLogViewTest(ModelViewTestCase): def test_delete_object(self): site = Site( - name='Test Site 1', - slug='test-site-1', + name='Site 1', + slug='site-1', custom_field_data={ 'my_field': 'ABC', 'my_field_select': 'Bar' @@ -137,13 +137,78 @@ class ChangeLogViewTest(ModelViewTestCase): self.assertEqual(oc.prechange_data['tags'], ['Tag 1', 'Tag 2']) self.assertEqual(oc.postchange_data, None) - # TODO: Add tests for bulk edit, bulk delete views + def test_bulk_update_objects(self): + sites = ( + Site(name='Site 1', slug='site-1', status=SiteStatusChoices.STATUS_ACTIVE), + Site(name='Site 2', slug='site-2', status=SiteStatusChoices.STATUS_ACTIVE), + Site(name='Site 3', slug='site-3', status=SiteStatusChoices.STATUS_ACTIVE), + ) + Site.objects.bulk_create(sites) + + form_data = { + 'pk': [site.pk for site in sites], + '_apply': True, + 'status': SiteStatusChoices.STATUS_PLANNED, + 'description': 'New description', + } + + request = { + 'path': self._get_url('bulk_edit'), + 'data': post_data(form_data), + } + self.add_permissions('dcim.change_site') + response = self.client.post(**request) + self.assertHttpStatus(response, 302) + + objectchange = ObjectChange.objects.get( + changed_object_type=ContentType.objects.get_for_model(Site), + changed_object_id=sites[0].pk + ) + self.assertEqual(objectchange.changed_object, sites[0]) + self.assertEqual(objectchange.action, ObjectChangeActionChoices.ACTION_UPDATE) + self.assertEqual(objectchange.prechange_data['status'], SiteStatusChoices.STATUS_ACTIVE) + self.assertEqual(objectchange.prechange_data['description'], '') + self.assertEqual(objectchange.postchange_data['status'], form_data['status']) + self.assertEqual(objectchange.postchange_data['description'], form_data['description']) + + def test_bulk_delete_objects(self): + sites = ( + Site(name='Site 1', slug='site-1', status=SiteStatusChoices.STATUS_ACTIVE), + Site(name='Site 2', slug='site-2', status=SiteStatusChoices.STATUS_ACTIVE), + Site(name='Site 3', slug='site-3', status=SiteStatusChoices.STATUS_ACTIVE), + ) + Site.objects.bulk_create(sites) + + form_data = { + 'pk': [site.pk for site in sites], + 'confirm': True, + '_confirm': True, + } + + request = { + 'path': self._get_url('bulk_delete'), + 'data': post_data(form_data), + } + self.add_permissions('dcim.delete_site') + response = self.client.post(**request) + self.assertHttpStatus(response, 302) + + objectchange = ObjectChange.objects.get( + changed_object_type=ContentType.objects.get_for_model(Site), + changed_object_id=sites[0].pk + ) + self.assertEqual(objectchange.changed_object_type, ContentType.objects.get_for_model(Site)) + self.assertEqual(objectchange.changed_object_id, sites[0].pk) + self.assertEqual(objectchange.action, ObjectChangeActionChoices.ACTION_DELETE) + self.assertEqual(objectchange.prechange_data['name'], sites[0].name) + self.assertEqual(objectchange.prechange_data['slug'], sites[0].slug) + self.assertEqual(objectchange.postchange_data, None) class ChangeLogAPITest(APITestCase): - def setUp(self): - super().setUp() + @classmethod + def setUpTestData(cls): # Create a custom field on the Site model ct = ContentType.objects.get_for_model(Site) @@ -175,8 +240,8 @@ class ChangeLogAPITest(APITestCase): def test_create_object(self): data = { - 'name': 'Test Site 1', - 'slug': 'test-site-1', + 'name': 'Site 1', + 'slug': 'site-1', 'custom_fields': { 'my_field': 'ABC', 'my_field_select': 'Bar', @@ -207,12 +272,12 @@ class ChangeLogAPITest(APITestCase): self.assertEqual(oc_list[1].postchange_data['tags'], ['Tag 1', 'Tag 2']) def test_update_object(self): - site = Site(name='Test Site 1', slug='test-site-1') + site = Site(name='Site 1', slug='site-1') site.save() data = { - 'name': 'Test Site X', - 'slug': 'test-site-x', + 'name': 'Site X', + 'slug': 'site-x', 'custom_fields': { 'my_field': 'DEF', 'my_field_select': 'Foo', @@ -241,8 +306,8 @@ class ChangeLogAPITest(APITestCase): def test_delete_object(self): site = Site( - name='Test Site 1', - slug='test-site-1', + name='Site 1', + slug='site-1', custom_field_data={ 'my_field': 'ABC', 'my_field_select': 'Bar' @@ -267,4 +332,118 @@ class ChangeLogAPITest(APITestCase): self.assertEqual(oc.prechange_data['tags'], ['Tag 1', 'Tag 2']) self.assertEqual(oc.postchange_data, None) - # TODO: Add tests for bulk edit, bulk delete views + def test_bulk_create_objects(self): + data = ( + { + 'name': 'Site 1', + 'slug': 'site-1', + }, + { + 'name': 'Site 2', + 'slug': 'site-2', + }, + { + 'name': 'Site 3', + 'slug': 'site-3', + }, + ) + self.assertEqual(ObjectChange.objects.count(), 0) + url = reverse('dcim-api:site-list') + self.add_permissions('dcim.add_site') + + response = self.client.post(url, data, format='json', **self.header) + self.assertHttpStatus(response, status.HTTP_201_CREATED) + self.assertEqual(ObjectChange.objects.count(), 3) + + site1 = Site.objects.get(pk=response.data[0]['id']) + objectchange = ObjectChange.objects.get( + changed_object_type=ContentType.objects.get_for_model(Site), + changed_object_id=site1.pk + ) + self.assertEqual(objectchange.changed_object, site1) + self.assertEqual(objectchange.action, ObjectChangeActionChoices.ACTION_CREATE) + self.assertEqual(objectchange.prechange_data, None) + self.assertEqual(objectchange.postchange_data['name'], data[0]['name']) + self.assertEqual(objectchange.postchange_data['slug'], data[0]['slug']) + + def test_bulk_edit_objects(self): + sites = ( + Site(name='Site 1', slug='site-1'), + Site(name='Site 2', slug='site-2'), + Site(name='Site 3', slug='site-3'), + ) + Site.objects.bulk_create(sites) + + data = ( + { + 'id': sites[0].pk, + 'name': 'Site A', + 'slug': 'site-A', + }, + { + 'id': sites[1].pk, + 'name': 'Site B', + 'slug': 'site-b', + }, + { + 'id': sites[2].pk, + 'name': 'Site C', + 'slug': 'site-c', + }, + ) + self.assertEqual(ObjectChange.objects.count(), 0) + url = reverse('dcim-api:site-list') + self.add_permissions('dcim.change_site') + + response = self.client.patch(url, data, format='json', **self.header) + self.assertHttpStatus(response, status.HTTP_200_OK) + self.assertEqual(ObjectChange.objects.count(), 3) + + objectchange = ObjectChange.objects.get( + changed_object_type=ContentType.objects.get_for_model(Site), + changed_object_id=sites[0].pk + ) + self.assertEqual(objectchange.changed_object, sites[0]) + self.assertEqual(objectchange.action, ObjectChangeActionChoices.ACTION_UPDATE) + self.assertEqual(objectchange.prechange_data['name'], 'Site 1') + self.assertEqual(objectchange.prechange_data['slug'], 'site-1') + self.assertEqual(objectchange.postchange_data['name'], data[0]['name']) + self.assertEqual(objectchange.postchange_data['slug'], data[0]['slug']) + + def test_bulk_delete_objects(self): + sites = ( + Site(name='Site 1', slug='site-1'), + Site(name='Site 2', slug='site-2'), + Site(name='Site 3', slug='site-3'), + ) + Site.objects.bulk_create(sites) + + data = ( + { + 'id': sites[0].pk, + }, + { + 'id': sites[1].pk, + }, + { + 'id': sites[2].pk, + }, + ) + self.assertEqual(ObjectChange.objects.count(), 0) + url = reverse('dcim-api:site-list') + self.add_permissions('dcim.delete_site') + + response = self.client.delete(url, data, format='json', **self.header) + self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT) + self.assertEqual(ObjectChange.objects.count(), 3) + + objectchange = ObjectChange.objects.get( + changed_object_type=ContentType.objects.get_for_model(Site), + changed_object_id=sites[0].pk + ) + self.assertEqual(objectchange.changed_object_type, ContentType.objects.get_for_model(Site)) + self.assertEqual(objectchange.changed_object_id, sites[0].pk) + self.assertEqual(objectchange.action, ObjectChangeActionChoices.ACTION_DELETE) + self.assertEqual(objectchange.prechange_data['name'], 'Site 1') + self.assertEqual(objectchange.prechange_data['slug'], 'site-1') + self.assertEqual(objectchange.postchange_data, None)