Merge pull request #4072 from netbox-community/4000-view-tests

Closes #4000: Add tests for the create, edit, and delete views of all models
This commit is contained in:
Jeremy Stretch 2020-01-31 16:07:32 -05:00 committed by GitHub
commit ce081a6e15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1112 additions and 1238 deletions

View File

@ -1,23 +1,15 @@
import urllib.parse import datetime
from django.test import Client, TestCase
from django.urls import reverse
from circuits.choices import *
from circuits.models import Circuit, CircuitType, Provider from circuits.models import Circuit, CircuitType, Provider
from utilities.testing import create_test_user from utilities.testing import StandardTestCases
class ProviderTestCase(TestCase): class ProviderTestCase(StandardTestCases.Views):
model = Provider
def setUp(self): @classmethod
user = create_test_user( def setUpTestData(cls):
permissions=[
'circuits.view_provider',
'circuits.add_provider',
]
)
self.client = Client()
self.client.force_login(user)
Provider.objects.bulk_create([ Provider.objects.bulk_create([
Provider(name='Provider 1', slug='provider-1', asn=65001), Provider(name='Provider 1', slug='provider-1', asn=65001),
@ -25,48 +17,35 @@ class ProviderTestCase(TestCase):
Provider(name='Provider 3', slug='provider-3', asn=65003), Provider(name='Provider 3', slug='provider-3', asn=65003),
]) ])
def test_provider_list(self): cls.form_data = {
'name': 'Provider X',
url = reverse('circuits:provider_list') 'slug': 'provider-x',
params = { 'asn': 65123,
"q": "test", 'account': '1234',
'portal_url': 'http://example.com/portal',
'noc_contact': 'noc@example.com',
'admin_contact': 'admin@example.com',
'comments': 'Another provider',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_provider(self):
provider = Provider.objects.first()
response = self.client.get(provider.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_provider_import(self):
csv_data = (
"name,slug", "name,slug",
"Provider 4,provider-4", "Provider 4,provider-4",
"Provider 5,provider-5", "Provider 5,provider-5",
"Provider 6,provider-6", "Provider 6,provider-6",
) )
response = self.client.post(reverse('circuits:provider_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class CircuitTypeTestCase(StandardTestCases.Views):
self.assertEqual(Provider.objects.count(), 6) model = CircuitType
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
class CircuitTypeTestCase(TestCase): @classmethod
def setUpTestData(cls):
def setUp(self):
user = create_test_user(
permissions=[
'circuits.view_circuittype',
'circuits.add_circuittype',
]
)
self.client = Client()
self.client.force_login(user)
CircuitType.objects.bulk_create([ CircuitType.objects.bulk_create([
CircuitType(name='Circuit Type 1', slug='circuit-type-1'), CircuitType(name='Circuit Type 1', slug='circuit-type-1'),
@ -74,39 +53,25 @@ class CircuitTypeTestCase(TestCase):
CircuitType(name='Circuit Type 3', slug='circuit-type-3'), CircuitType(name='Circuit Type 3', slug='circuit-type-3'),
]) ])
def test_circuittype_list(self): cls.form_data = {
'name': 'Circuit Type X',
'slug': 'circuit-type-x',
'description': 'A new circuit type',
}
url = reverse('circuits:circuittype_list') cls.csv_data = (
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_circuittype_import(self):
csv_data = (
"name,slug", "name,slug",
"Circuit Type 4,circuit-type-4", "Circuit Type 4,circuit-type-4",
"Circuit Type 5,circuit-type-5", "Circuit Type 5,circuit-type-5",
"Circuit Type 6,circuit-type-6", "Circuit Type 6,circuit-type-6",
) )
response = self.client.post(reverse('circuits:circuittype_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class CircuitTestCase(StandardTestCases.Views):
self.assertEqual(CircuitType.objects.count(), 6) model = Circuit
@classmethod
class CircuitTestCase(TestCase): def setUpTestData(cls):
def setUp(self):
user = create_test_user(
permissions=[
'circuits.view_circuit',
'circuits.add_circuit',
]
)
self.client = Client()
self.client.force_login(user)
provider = Provider(name='Provider 1', slug='provider-1', asn=65001) provider = Provider(name='Provider 1', slug='provider-1', asn=65001)
provider.save() provider.save()
@ -120,33 +85,22 @@ class CircuitTestCase(TestCase):
Circuit(cid='Circuit 3', provider=provider, type=circuittype), Circuit(cid='Circuit 3', provider=provider, type=circuittype),
]) ])
def test_circuit_list(self): cls.form_data = {
'cid': 'Circuit X',
url = reverse('circuits:circuit_list') 'provider': provider.pk,
params = { 'type': circuittype.pk,
"provider": Provider.objects.first().slug, 'status': CircuitStatusChoices.STATUS_ACTIVE,
"type": CircuitType.objects.first().slug, 'tenant': None,
'install_date': datetime.date(2020, 1, 1),
'commit_rate': 1000,
'description': 'A new circuit',
'comments': 'Some comments',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_circuit(self):
circuit = Circuit.objects.first()
response = self.client.get(circuit.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_circuit_import(self):
csv_data = (
"cid,provider,type", "cid,provider,type",
"Circuit 4,Provider 1,Circuit Type 1", "Circuit 4,Provider 1,Circuit Type 1",
"Circuit 5,Provider 1,Circuit Type 1", "Circuit 5,Provider 1,Circuit Type 1",
"Circuit 6,Provider 1,Circuit Type 1", "Circuit 6,Provider 1,Circuit Type 1",
) )
response = self.client.post(reverse('circuits:circuit_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200)
self.assertEqual(Circuit.objects.count(), 6)

View File

@ -1549,6 +1549,7 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
) )
manufacturer = forms.ModelChoiceField( manufacturer = forms.ModelChoiceField(
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
required=False,
widget=APISelect( widget=APISelect(
api_url="/api/dcim/manufacturers/", api_url="/api/dcim/manufacturers/",
filter_for={ filter_for={

File diff suppressed because it is too large Load Diff

View File

@ -2,48 +2,55 @@ import urllib.parse
import uuid import uuid
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import Client, TestCase
from django.urls import reverse from django.urls import reverse
from dcim.models import Site from dcim.models import Site
from extras.choices import ObjectChangeActionChoices from extras.choices import ObjectChangeActionChoices
from extras.models import ConfigContext, ObjectChange, Tag from extras.models import ConfigContext, ObjectChange, Tag
from utilities.testing import create_test_user from utilities.testing import StandardTestCases, TestCase
class TagTestCase(TestCase): class TagTestCase(StandardTestCases.Views):
model = Tag
def setUp(self): # Disable inapplicable tests
user = create_test_user(permissions=['extras.view_tag']) test_create_object = None
self.client = Client() test_import_objects = None
self.client.force_login(user)
Tag.objects.bulk_create([ # TODO: Restore test when #4071 is resolved
test_get_object = None
@classmethod
def setUpTestData(cls):
Tag.objects.bulk_create((
Tag(name='Tag 1', slug='tag-1'), Tag(name='Tag 1', slug='tag-1'),
Tag(name='Tag 2', slug='tag-2'), Tag(name='Tag 2', slug='tag-2'),
Tag(name='Tag 3', slug='tag-3'), Tag(name='Tag 3', slug='tag-3'),
]) ))
def test_tag_list(self): cls.form_data = {
'name': 'Tag X',
url = reverse('extras:tag_list') 'slug': 'tag-x',
params = { 'color': 'c0c0c0',
"q": "tag", 'comments': 'Some comments',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
self.assertEqual(response.status_code, 200)
class ConfigContextTestCase(StandardTestCases.Views):
model = ConfigContext
class ConfigContextTestCase(TestCase): # Disable inapplicable tests
test_import_objects = None
def setUp(self): # TODO: Resolve model discrepancies when creating/editing ConfigContexts
user = create_test_user(permissions=['extras.view_configcontext']) test_create_object = None
self.client = Client() test_edit_object = None
self.client.force_login(user)
site = Site(name='Site 1', slug='site-1') @classmethod
site.save() def setUpTestData(cls):
site = Site.objects.create(name='Site 1', slug='site-1')
# Create three ConfigContexts # Create three ConfigContexts
for i in range(1, 4): for i in range(1, 4):
@ -54,34 +61,35 @@ class ConfigContextTestCase(TestCase):
configcontext.save() configcontext.save()
configcontext.sites.add(site) configcontext.sites.add(site)
def test_configcontext_list(self): cls.form_data = {
'name': 'Config Context X',
url = reverse('extras:configcontext_list') 'weight': 200,
params = { 'description': 'A new config context',
"q": "foo", 'is_active': True,
'regions': [],
'sites': [site.pk],
'roles': [],
'platforms': [],
'tenant_groups': [],
'tenants': [],
'tags': [],
'data': '{"foo": 123}',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
self.assertEqual(response.status_code, 200)
def test_configcontext(self):
configcontext = ConfigContext.objects.first()
response = self.client.get(configcontext.get_absolute_url())
self.assertEqual(response.status_code, 200)
class ObjectChangeTestCase(TestCase): class ObjectChangeTestCase(TestCase):
user_permissions = (
'extras.view_objectchange',
)
def setUp(self): @classmethod
user = create_test_user(permissions=['extras.view_objectchange']) def setUpTestData(cls):
self.client = Client()
self.client.force_login(user)
site = Site(name='Site 1', slug='site-1') site = Site(name='Site 1', slug='site-1')
site.save() site.save()
# Create three ObjectChanges # Create three ObjectChanges
user = User.objects.create_user(username='testuser2')
for i in range(1, 4): for i in range(1, 4):
oc = site.to_objectchange(action=ObjectChangeActionChoices.ACTION_UPDATE) oc = site.to_objectchange(action=ObjectChangeActionChoices.ACTION_UPDATE)
oc.user = user oc.user = user
@ -96,10 +104,10 @@ class ObjectChangeTestCase(TestCase):
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
self.assertEqual(response.status_code, 200) self.assertHttpStatus(response, 200)
def test_objectchange(self): def test_objectchange(self):
objectchange = ObjectChange.objects.first() objectchange = ObjectChange.objects.first()
response = self.client.get(objectchange.get_absolute_url()) response = self.client.get(objectchange.get_absolute_url())
self.assertEqual(response.status_code, 200) self.assertHttpStatus(response, 200)

View File

@ -1,26 +1,18 @@
from netaddr import IPNetwork import datetime
import urllib.parse
from django.test import Client, TestCase from netaddr import IPNetwork
from django.urls import reverse
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
from ipam.choices import ServiceProtocolChoices from ipam.choices import *
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
from utilities.testing import create_test_user from utilities.testing import StandardTestCases
class VRFTestCase(TestCase): class VRFTestCase(StandardTestCases.Views):
model = VRF
def setUp(self): @classmethod
user = create_test_user( def setUpTestData(cls):
permissions=[
'ipam.view_vrf',
'ipam.add_vrf',
]
)
self.client = Client()
self.client.force_login(user)
VRF.objects.bulk_create([ VRF.objects.bulk_create([
VRF(name='VRF 1', rd='65000:1'), VRF(name='VRF 1', rd='65000:1'),
@ -28,48 +20,32 @@ class VRFTestCase(TestCase):
VRF(name='VRF 3', rd='65000:3'), VRF(name='VRF 3', rd='65000:3'),
]) ])
def test_vrf_list(self): cls.form_data = {
'name': 'VRF X',
url = reverse('ipam:vrf_list') 'rd': '65000:999',
params = { 'tenant': None,
"q": "65000", 'enforce_unique': True,
'description': 'A new VRF',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_vrf(self):
vrf = VRF.objects.first()
response = self.client.get(vrf.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_vrf_import(self):
csv_data = (
"name", "name",
"VRF 4", "VRF 4",
"VRF 5", "VRF 5",
"VRF 6", "VRF 6",
) )
response = self.client.post(reverse('ipam:vrf_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class RIRTestCase(StandardTestCases.Views):
self.assertEqual(VRF.objects.count(), 6) model = RIR
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
class RIRTestCase(TestCase): @classmethod
def setUpTestData(cls):
def setUp(self):
user = create_test_user(
permissions=[
'ipam.view_rir',
'ipam.add_rir',
]
)
self.client = Client()
self.client.force_login(user)
RIR.objects.bulk_create([ RIR.objects.bulk_create([
RIR(name='RIR 1', slug='rir-1'), RIR(name='RIR 1', slug='rir-1'),
@ -77,42 +53,27 @@ class RIRTestCase(TestCase):
RIR(name='RIR 3', slug='rir-3'), RIR(name='RIR 3', slug='rir-3'),
]) ])
def test_rir_list(self): cls.form_data = {
'name': 'RIR X',
'slug': 'rir-x',
'is_private': True,
}
url = reverse('ipam:rir_list') cls.csv_data = (
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_rir_import(self):
csv_data = (
"name,slug", "name,slug",
"RIR 4,rir-4", "RIR 4,rir-4",
"RIR 5,rir-5", "RIR 5,rir-5",
"RIR 6,rir-6", "RIR 6,rir-6",
) )
response = self.client.post(reverse('ipam:rir_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class AggregateTestCase(StandardTestCases.Views):
self.assertEqual(RIR.objects.count(), 6) model = Aggregate
@classmethod
def setUpTestData(cls):
class AggregateTestCase(TestCase): rir = RIR.objects.create(name='RIR 1', slug='rir-1')
def setUp(self):
user = create_test_user(
permissions=[
'ipam.view_aggregate',
'ipam.add_aggregate',
]
)
self.client = Client()
self.client.force_login(user)
rir = RIR(name='RIR 1', slug='rir-1')
rir.save()
Aggregate.objects.bulk_create([ Aggregate.objects.bulk_create([
Aggregate(family=4, prefix=IPNetwork('10.1.0.0/16'), rir=rir), Aggregate(family=4, prefix=IPNetwork('10.1.0.0/16'), rir=rir),
@ -120,48 +81,32 @@ class AggregateTestCase(TestCase):
Aggregate(family=4, prefix=IPNetwork('10.3.0.0/16'), rir=rir), Aggregate(family=4, prefix=IPNetwork('10.3.0.0/16'), rir=rir),
]) ])
def test_aggregate_list(self): cls.form_data = {
'family': 4,
url = reverse('ipam:aggregate_list') 'prefix': IPNetwork('10.99.0.0/16'),
params = { 'rir': rir.pk,
"rir": RIR.objects.first().slug, 'date_added': datetime.date(2020, 1, 1),
'description': 'A new aggregate',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_aggregate(self):
aggregate = Aggregate.objects.first()
response = self.client.get(aggregate.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_aggregate_import(self):
csv_data = (
"prefix,rir", "prefix,rir",
"10.4.0.0/16,RIR 1", "10.4.0.0/16,RIR 1",
"10.5.0.0/16,RIR 1", "10.5.0.0/16,RIR 1",
"10.6.0.0/16,RIR 1", "10.6.0.0/16,RIR 1",
) )
response = self.client.post(reverse('ipam:aggregate_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class RoleTestCase(StandardTestCases.Views):
self.assertEqual(Aggregate.objects.count(), 6) model = Role
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
class RoleTestCase(TestCase): @classmethod
def setUpTestData(cls):
def setUp(self):
user = create_test_user(
permissions=[
'ipam.view_role',
'ipam.add_role',
]
)
self.client = Client()
self.client.force_login(user)
Role.objects.bulk_create([ Role.objects.bulk_create([
Role(name='Role 1', slug='role-1'), Role(name='Role 1', slug='role-1'),
@ -169,42 +114,31 @@ class RoleTestCase(TestCase):
Role(name='Role 3', slug='role-3'), Role(name='Role 3', slug='role-3'),
]) ])
def test_role_list(self): cls.form_data = {
'name': 'Role X',
'slug': 'role-x',
'weight': 200,
'description': 'A new role',
}
url = reverse('ipam:role_list') cls.csv_data = (
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_role_import(self):
csv_data = (
"name,slug,weight", "name,slug,weight",
"Role 4,role-4,1000", "Role 4,role-4,1000",
"Role 5,role-5,1000", "Role 5,role-5,1000",
"Role 6,role-6,1000", "Role 6,role-6,1000",
) )
response = self.client.post(reverse('ipam:role_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class PrefixTestCase(StandardTestCases.Views):
self.assertEqual(Role.objects.count(), 6) model = Prefix
@classmethod
def setUpTestData(cls):
class PrefixTestCase(TestCase): site = Site.objects.create(name='Site 1', slug='site-1')
vrf = VRF.objects.create(name='VRF 1', rd='65000:1')
def setUp(self): role = Role.objects.create(name='Role 1', slug='role-1')
user = create_test_user( # vlan = VLAN.objects.create(vid=123, name='VLAN 123')
permissions=[
'ipam.view_prefix',
'ipam.add_prefix',
]
)
self.client = Client()
self.client.force_login(user)
site = Site(name='Site 1', slug='site-1')
site.save()
Prefix.objects.bulk_create([ Prefix.objects.bulk_create([
Prefix(family=4, prefix=IPNetwork('10.1.0.0/16'), site=site), Prefix(family=4, prefix=IPNetwork('10.1.0.0/16'), site=site),
@ -212,51 +146,34 @@ class PrefixTestCase(TestCase):
Prefix(family=4, prefix=IPNetwork('10.3.0.0/16'), site=site), Prefix(family=4, prefix=IPNetwork('10.3.0.0/16'), site=site),
]) ])
def test_prefix_list(self): cls.form_data = {
'prefix': IPNetwork('192.0.2.0/24'),
url = reverse('ipam:prefix_list') 'site': site.pk,
params = { 'vrf': vrf.pk,
"site": Site.objects.first().slug, 'tenant': None,
'vlan': None,
'status': PrefixStatusChoices.STATUS_RESERVED,
'role': role.pk,
'is_pool': True,
'description': 'A new prefix',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_prefix(self):
prefix = Prefix.objects.first()
response = self.client.get(prefix.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_prefix_import(self):
csv_data = (
"prefix,status", "prefix,status",
"10.4.0.0/16,Active", "10.4.0.0/16,Active",
"10.5.0.0/16,Active", "10.5.0.0/16,Active",
"10.6.0.0/16,Active", "10.6.0.0/16,Active",
) )
response = self.client.post(reverse('ipam:prefix_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class IPAddressTestCase(StandardTestCases.Views):
self.assertEqual(Prefix.objects.count(), 6) model = IPAddress
@classmethod
def setUpTestData(cls):
class IPAddressTestCase(TestCase): vrf = VRF.objects.create(name='VRF 1', rd='65000:1')
def setUp(self):
user = create_test_user(
permissions=[
'ipam.view_ipaddress',
'ipam.add_ipaddress',
]
)
self.client = Client()
self.client.force_login(user)
vrf = VRF(name='VRF 1', rd='65000:1')
vrf.save()
IPAddress.objects.bulk_create([ IPAddress.objects.bulk_create([
IPAddress(family=4, address=IPNetwork('192.0.2.1/24'), vrf=vrf), IPAddress(family=4, address=IPNetwork('192.0.2.1/24'), vrf=vrf),
@ -264,51 +181,38 @@ class IPAddressTestCase(TestCase):
IPAddress(family=4, address=IPNetwork('192.0.2.3/24'), vrf=vrf), IPAddress(family=4, address=IPNetwork('192.0.2.3/24'), vrf=vrf),
]) ])
def test_ipaddress_list(self): cls.form_data = {
'vrf': vrf.pk,
url = reverse('ipam:ipaddress_list') 'address': IPNetwork('192.0.2.99/24'),
params = { 'tenant': None,
"vrf": VRF.objects.first().rd, 'status': IPAddressStatusChoices.STATUS_RESERVED,
'role': IPAddressRoleChoices.ROLE_ANYCAST,
'interface': None,
'nat_inside': None,
'dns_name': 'example',
'description': 'A new IP address',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_ipaddress(self):
ipaddress = IPAddress.objects.first()
response = self.client.get(ipaddress.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_ipaddress_import(self):
csv_data = (
"address,status", "address,status",
"192.0.2.4/24,Active", "192.0.2.4/24,Active",
"192.0.2.5/24,Active", "192.0.2.5/24,Active",
"192.0.2.6/24,Active", "192.0.2.6/24,Active",
) )
response = self.client.post(reverse('ipam:ipaddress_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class VLANGroupTestCase(StandardTestCases.Views):
self.assertEqual(IPAddress.objects.count(), 6) model = VLANGroup
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
class VLANGroupTestCase(TestCase): @classmethod
def setUpTestData(cls):
def setUp(self): site = Site.objects.create(name='Site 1', slug='site-1')
user = create_test_user(
permissions=[
'ipam.view_vlangroup',
'ipam.add_vlangroup',
]
)
self.client = Client()
self.client.force_login(user)
site = Site(name='Site 1', slug='site-1')
site.save()
VLANGroup.objects.bulk_create([ VLANGroup.objects.bulk_create([
VLANGroup(name='VLAN Group 1', slug='vlan-group-1', site=site), VLANGroup(name='VLAN Group 1', slug='vlan-group-1', site=site),
@ -316,45 +220,29 @@ class VLANGroupTestCase(TestCase):
VLANGroup(name='VLAN Group 3', slug='vlan-group-3', site=site), VLANGroup(name='VLAN Group 3', slug='vlan-group-3', site=site),
]) ])
def test_vlangroup_list(self): cls.form_data = {
'name': 'VLAN Group X',
url = reverse('ipam:vlangroup_list') 'slug': 'vlan-group-x',
params = { 'site': site.pk,
"site": Site.objects.first().slug,
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_vlangroup_import(self):
csv_data = (
"name,slug", "name,slug",
"VLAN Group 4,vlan-group-4", "VLAN Group 4,vlan-group-4",
"VLAN Group 5,vlan-group-5", "VLAN Group 5,vlan-group-5",
"VLAN Group 6,vlan-group-6", "VLAN Group 6,vlan-group-6",
) )
response = self.client.post(reverse('ipam:vlangroup_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class VLANTestCase(StandardTestCases.Views):
self.assertEqual(VLANGroup.objects.count(), 6) model = VLAN
@classmethod
def setUpTestData(cls):
class VLANTestCase(TestCase): site = Site.objects.create(name='Site 1', slug='site-1')
vlangroup = VLANGroup.objects.create(name='VLAN Group 1', slug='vlan-group-1', site=site)
def setUp(self): role = Role.objects.create(name='Role 1', slug='role-1')
user = create_test_user(
permissions=[
'ipam.view_vlan',
'ipam.add_vlan',
]
)
self.client = Client()
self.client.force_login(user)
vlangroup = VLANGroup(name='VLAN Group 1', slug='vlan-group-1')
vlangroup.save()
VLAN.objects.bulk_create([ VLAN.objects.bulk_create([
VLAN(group=vlangroup, vid=101, name='VLAN101'), VLAN(group=vlangroup, vid=101, name='VLAN101'),
@ -362,58 +250,43 @@ class VLANTestCase(TestCase):
VLAN(group=vlangroup, vid=103, name='VLAN103'), VLAN(group=vlangroup, vid=103, name='VLAN103'),
]) ])
def test_vlan_list(self): cls.form_data = {
'site': site.pk,
url = reverse('ipam:vlan_list') 'group': vlangroup.pk,
params = { 'vid': 999,
"group": VLANGroup.objects.first().slug, 'name': 'VLAN999',
'tenant': None,
'status': VLANStatusChoices.STATUS_RESERVED,
'role': role.pk,
'description': 'A new VLAN',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_vlan(self):
vlan = VLAN.objects.first()
response = self.client.get(vlan.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_vlan_import(self):
csv_data = (
"vid,name,status", "vid,name,status",
"104,VLAN104,Active", "104,VLAN104,Active",
"105,VLAN105,Active", "105,VLAN105,Active",
"106,VLAN106,Active", "106,VLAN106,Active",
) )
response = self.client.post(reverse('ipam:vlan_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class ServiceTestCase(StandardTestCases.Views):
self.assertEqual(VLAN.objects.count(), 6) model = Service
# Disable inapplicable tests
test_import_objects = None
class ServiceTestCase(TestCase): # TODO: Resolve URL for Service creation
test_create_object = None
def setUp(self): @classmethod
user = create_test_user(permissions=['ipam.view_service']) def setUpTestData(cls):
self.client = Client()
self.client.force_login(user)
site = Site(name='Site 1', slug='site-1') site = Site.objects.create(name='Site 1', slug='site-1')
site.save() manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1')
manufacturer = Manufacturer(name='Manufacturer 1', slug='manufacturer-1') devicerole = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
manufacturer.save() device = Device.objects.create(name='Device 1', site=site, device_type=devicetype, device_role=devicerole)
devicetype = DeviceType(manufacturer=manufacturer, model='Device Type 1')
devicetype.save()
devicerole = DeviceRole(name='Device Role 1', slug='device-role-1')
devicerole.save()
device = Device(name='Device 1', site=site, device_type=devicetype, device_role=devicerole)
device.save()
Service.objects.bulk_create([ Service.objects.bulk_create([
Service(device=device, name='Service 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=101), Service(device=device, name='Service 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=101),
@ -421,18 +294,13 @@ class ServiceTestCase(TestCase):
Service(device=device, name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=103), Service(device=device, name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=103),
]) ])
def test_service_list(self): cls.form_data = {
'device': device.pk,
url = reverse('ipam:service_list') 'virtual_machine': None,
params = { 'name': 'Service X',
"device_id": Device.objects.first(), 'protocol': ServiceProtocolChoices.PROTOCOL_TCP,
'port': 999,
'ipaddresses': [],
'description': 'A new service',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
self.assertEqual(response.status_code, 200)
def test_service(self):
service = Service.objects.first()
response = self.client.get(service.get_absolute_url())
self.assertEqual(response.status_code, 200)

View File

@ -1,6 +1,6 @@
import urllib.parse import urllib.parse
from django.test import TestCase from utilities.testing import TestCase
from django.urls import reverse from django.urls import reverse
@ -11,7 +11,7 @@ class HomeViewTestCase(TestCase):
url = reverse('home') url = reverse('home')
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 200) self.assertHttpStatus(response, 200)
def test_search(self): def test_search(self):
@ -21,4 +21,4 @@ class HomeViewTestCase(TestCase):
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
self.assertEqual(response.status_code, 200) self.assertHttpStatus(response, 200)

View File

@ -1,26 +1,22 @@
import base64 import base64
import urllib.parse
from django.test import Client, TestCase
from django.urls import reverse from django.urls import reverse
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
from secrets.models import Secret, SecretRole, SessionKey, UserKey from secrets.models import Secret, SecretRole, SessionKey, UserKey
from utilities.testing import create_test_user from utilities.testing import StandardTestCases
from .constants import PRIVATE_KEY, PUBLIC_KEY from .constants import PRIVATE_KEY, PUBLIC_KEY
class SecretRoleTestCase(TestCase): class SecretRoleTestCase(StandardTestCases.Views):
model = SecretRole
def setUp(self): # Disable inapplicable tests
user = create_test_user( test_get_object = None
permissions=[ test_delete_object = None
'secrets.view_secretrole',
'secrets.add_secretrole', @classmethod
] def setUpTestData(cls):
)
self.client = Client()
self.client.force_login(user)
SecretRole.objects.bulk_create([ SecretRole.objects.bulk_create([
SecretRole(name='Secret Role 1', slug='secret-role-1'), SecretRole(name='Secret Role 1', slug='secret-role-1'),
@ -28,65 +24,40 @@ class SecretRoleTestCase(TestCase):
SecretRole(name='Secret Role 3', slug='secret-role-3'), SecretRole(name='Secret Role 3', slug='secret-role-3'),
]) ])
def test_secretrole_list(self): cls.form_data = {
'name': 'Secret Role X',
'slug': 'secret-role-x',
'description': 'A secret role',
'users': [],
'groups': [],
}
url = reverse('secrets:secretrole_list') cls.csv_data = (
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200)
def test_secretrole_import(self):
csv_data = (
"name,slug", "name,slug",
"Secret Role 4,secret-role-4", "Secret Role 4,secret-role-4",
"Secret Role 5,secret-role-5", "Secret Role 5,secret-role-5",
"Secret Role 6,secret-role-6", "Secret Role 6,secret-role-6",
) )
response = self.client.post(reverse('secrets:secretrole_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class SecretTestCase(StandardTestCases.Views):
self.assertEqual(SecretRole.objects.count(), 6) model = Secret
# Disable inapplicable tests
test_create_object = None
class SecretTestCase(TestCase): # TODO: Check permissions enforcement on secrets.views.secret_edit
test_edit_object = None
def setUp(self): @classmethod
user = create_test_user( def setUpTestData(cls):
permissions=[
'secrets.view_secret',
'secrets.add_secret',
]
)
# Set up a master key site = Site.objects.create(name='Site 1', slug='site-1')
userkey = UserKey(user=user, public_key=PUBLIC_KEY) manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
userkey.save() devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1')
master_key = userkey.get_master_key(PRIVATE_KEY) devicerole = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
self.session_key = SessionKey(userkey=userkey) device = Device.objects.create(name='Device 1', site=site, device_type=devicetype, device_role=devicerole)
self.session_key.save(master_key) secretrole = SecretRole.objects.create(name='Secret Role 1', slug='secret-role-1')
self.client = Client()
self.client.force_login(user)
site = Site(name='Site 1', slug='site-1')
site.save()
manufacturer = Manufacturer(name='Manufacturer 1', slug='manufacturer-1')
manufacturer.save()
devicetype = DeviceType(manufacturer=manufacturer, model='Device Type 1')
devicetype.save()
devicerole = DeviceRole(name='Device Role 1', slug='device-role-1')
devicerole.save()
device = Device(name='Device 1', site=site, device_type=devicetype, device_role=devicerole)
device.save()
secretrole = SecretRole(name='Secret Role 1', slug='secret-role-1')
secretrole.save()
Secret.objects.bulk_create([ Secret.objects.bulk_create([
Secret(device=device, role=secretrole, name='Secret 1', ciphertext=b'1234567890'), Secret(device=device, role=secretrole, name='Secret 1', ciphertext=b'1234567890'),
@ -94,23 +65,25 @@ class SecretTestCase(TestCase):
Secret(device=device, role=secretrole, name='Secret 3', ciphertext=b'1234567890'), Secret(device=device, role=secretrole, name='Secret 3', ciphertext=b'1234567890'),
]) ])
def test_secret_list(self): cls.form_data = {
'device': device.pk,
url = reverse('secrets:secret_list') 'role': secretrole.pk,
params = { 'name': 'Secret X',
"role": SecretRole.objects.first().slug,
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)), follow=True) def setUp(self):
self.assertEqual(response.status_code, 200)
def test_secret(self): super().setUp()
secret = Secret.objects.first() # Set up a master key for the test user
response = self.client.get(secret.get_absolute_url(), follow=True) userkey = UserKey(user=self.user, public_key=PUBLIC_KEY)
self.assertEqual(response.status_code, 200) userkey.save()
master_key = userkey.get_master_key(PRIVATE_KEY)
self.session_key = SessionKey(userkey=userkey)
self.session_key.save(master_key)
def test_secret_import(self): def test_import_objects(self):
self.add_permissions('secrets.add_secret')
csv_data = ( csv_data = (
"device,role,name,plaintext", "device,role,name,plaintext",
@ -125,5 +98,5 @@ class SecretTestCase(TestCase):
response = self.client.post(reverse('secrets:secret_import'), {'csv': '\n'.join(csv_data)}) response = self.client.post(reverse('secrets:secret_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) self.assertHttpStatus(response, 200)
self.assertEqual(Secret.objects.count(), 6) self.assertEqual(Secret.objects.count(), 6)

View File

@ -1,23 +1,16 @@
import urllib.parse
from django.test import Client, TestCase
from django.urls import reverse
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from utilities.testing import create_test_user from utilities.testing import StandardTestCases
class TenantGroupTestCase(TestCase): class TenantGroupTestCase(StandardTestCases.Views):
model = TenantGroup
def setUp(self): # Disable inapplicable tests
user = create_test_user( test_get_object = None
permissions=[ test_delete_object = None
'tenancy.view_tenantgroup',
'tenancy.add_tenantgroup', @classmethod
] def setUpTestData(cls):
)
self.client = Client()
self.client.force_login(user)
TenantGroup.objects.bulk_create([ TenantGroup.objects.bulk_create([
TenantGroup(name='Tenant Group 1', slug='tenant-group-1'), TenantGroup(name='Tenant Group 1', slug='tenant-group-1'),
@ -25,42 +18,26 @@ class TenantGroupTestCase(TestCase):
TenantGroup(name='Tenant Group 3', slug='tenant-group-3'), TenantGroup(name='Tenant Group 3', slug='tenant-group-3'),
]) ])
def test_tenantgroup_list(self): cls.form_data = {
'name': 'Tenant Group X',
'slug': 'tenant-group-x',
}
url = reverse('tenancy:tenantgroup_list') cls.csv_data = (
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200)
def test_tenantgroup_import(self):
csv_data = (
"name,slug", "name,slug",
"Tenant Group 4,tenant-group-4", "Tenant Group 4,tenant-group-4",
"Tenant Group 5,tenant-group-5", "Tenant Group 5,tenant-group-5",
"Tenant Group 6,tenant-group-6", "Tenant Group 6,tenant-group-6",
) )
response = self.client.post(reverse('tenancy:tenantgroup_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class TenantTestCase(StandardTestCases.Views):
self.assertEqual(TenantGroup.objects.count(), 6) model = Tenant
@classmethod
def setUpTestData(cls):
class TenantTestCase(TestCase): tenantgroup = TenantGroup.objects.create(name='Tenant Group 1', slug='tenant-group-1')
def setUp(self):
user = create_test_user(
permissions=[
'tenancy.view_tenant',
'tenancy.add_tenant',
]
)
self.client = Client()
self.client.force_login(user)
tenantgroup = TenantGroup(name='Tenant Group 1', slug='tenant-group-1')
tenantgroup.save()
Tenant.objects.bulk_create([ Tenant.objects.bulk_create([
Tenant(name='Tenant 1', slug='tenant-1', group=tenantgroup), Tenant(name='Tenant 1', slug='tenant-1', group=tenantgroup),
@ -68,32 +45,18 @@ class TenantTestCase(TestCase):
Tenant(name='Tenant 3', slug='tenant-3', group=tenantgroup), Tenant(name='Tenant 3', slug='tenant-3', group=tenantgroup),
]) ])
def test_tenant_list(self): cls.form_data = {
'name': 'Tenant X',
url = reverse('tenancy:tenant_list') 'slug': 'tenant-x',
params = { 'group': tenantgroup.pk,
"group": TenantGroup.objects.first().slug, 'description': 'A new tenant',
'comments': 'Some comments',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)), follow=True) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_tenant(self):
tenant = Tenant.objects.first()
response = self.client.get(tenant.get_absolute_url(), follow=True)
self.assertEqual(response.status_code, 200)
def test_tenant_import(self):
csv_data = (
"name,slug", "name,slug",
"Tenant 4,tenant-4", "Tenant 4,tenant-4",
"Tenant 5,tenant-5", "Tenant 5,tenant-5",
"Tenant 6,tenant-6", "Tenant 6,tenant-6",
) )
response = self.client.post(reverse('tenancy:tenant_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200)
self.assertEqual(Tenant.objects.count(), 6)

View File

@ -1,79 +0,0 @@
import logging
from contextlib import contextmanager
from django.contrib.auth.models import Permission, User
from rest_framework.test import APITestCase as _APITestCase
from users.models import Token
class APITestCase(_APITestCase):
def setUp(self):
"""
Create a superuser and token for API calls.
"""
self.user = User.objects.create(username='testuser', is_superuser=True)
self.token = Token.objects.create(user=self.user)
self.header = {'HTTP_AUTHORIZATION': 'Token {}'.format(self.token.key)}
def assertHttpStatus(self, response, expected_status):
"""
Provide more detail in the event of an unexpected HTTP response.
"""
err_message = "Expected HTTP status {}; received {}: {}"
self.assertEqual(response.status_code, expected_status, err_message.format(
expected_status, response.status_code, getattr(response, 'data', 'No data')
))
def create_test_user(username='testuser', permissions=list()):
"""
Create a User with the given permissions.
"""
user = User.objects.create_user(username=username)
for perm_name in permissions:
app, codename = perm_name.split('.')
perm = Permission.objects.get(content_type__app_label=app, codename=codename)
user.user_permissions.add(perm)
return user
def choices_to_dict(choices_list):
"""
Convert a list of field choices to a dictionary suitable for direct comparison with a ChoiceSet. For example:
[
{
"value": "choice-1",
"label": "First Choice"
},
{
"value": "choice-2",
"label": "Second Choice"
}
]
Becomes:
{
"choice-1": "First Choice",
"choice-2": "Second Choice
}
"""
return {
choice['value']: choice['label'] for choice in choices_list
}
@contextmanager
def disable_warnings(logger_name):
"""
Temporarily suppress expected warning messages to keep the test output clean.
"""
logger = logging.getLogger(logger_name)
current_level = logger.level
logger.setLevel(logging.ERROR)
yield
logger.setLevel(current_level)

View File

@ -0,0 +1,2 @@
from .testcases import *
from .utils import *

View File

@ -0,0 +1,249 @@
from django.contrib.auth.models import Permission, User
from django.core.exceptions import ObjectDoesNotExist
from django.test import Client, TestCase as _TestCase, override_settings
from django.urls import reverse, NoReverseMatch
from rest_framework.test import APIClient
from users.models import Token
from .utils import disable_warnings, model_to_dict, post_data
class TestCase(_TestCase):
user_permissions = ()
def setUp(self):
# Create the test user and assign permissions
self.user = User.objects.create_user(username='testuser')
self.add_permissions(*self.user_permissions)
# Initialize the test client
self.client = Client()
self.client.force_login(self.user)
#
# Permissions management
#
def add_permissions(self, *names):
"""
Assign a set of permissions to the test user. Accepts permission names in the form <app>.<action>_<model>.
"""
for name in names:
app, codename = name.split('.')
perm = Permission.objects.get(content_type__app_label=app, codename=codename)
self.user.user_permissions.add(perm)
def remove_permissions(self, *names):
"""
Remove a set of permissions from the test user, if assigned.
"""
for name in names:
app, codename = name.split('.')
perm = Permission.objects.get(content_type__app_label=app, codename=codename)
self.user.user_permissions.remove(perm)
#
# Convenience methods
#
def assertHttpStatus(self, response, expected_status):
"""
TestCase method. Provide more detail in the event of an unexpected HTTP response.
"""
err_message = "Expected HTTP status {}; received {}: {}"
self.assertEqual(response.status_code, expected_status, err_message.format(
expected_status, response.status_code, getattr(response, 'data', 'No data')
))
class APITestCase(TestCase):
client_class = APIClient
def setUp(self):
"""
Create a superuser and token for API calls.
"""
self.user = User.objects.create(username='testuser', is_superuser=True)
self.token = Token.objects.create(user=self.user)
self.header = {'HTTP_AUTHORIZATION': 'Token {}'.format(self.token.key)}
class StandardTestCases:
"""
We keep any TestCases with test_* methods inside a class to prevent unittest from trying to run them.
"""
class Views(TestCase):
"""
Stock TestCase suitable for testing all standard View functions:
- List objects
- View single object
- Create new object
- Modify existing object
- Delete existing object
- Import multiple new objects
"""
model = None
form_data = {}
csv_data = {}
maxDiff = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.model is None:
raise Exception("Test case requires model to be defined")
def _get_url(self, action, instance=None):
"""
Return the URL name for a specific action. An instance must be specified for
get/edit/delete views.
"""
url_format = '{}:{}_{{}}'.format(
self.model._meta.app_label,
self.model._meta.model_name
)
if action in ('list', 'add', 'import'):
return reverse(url_format.format(action))
elif action in ('get', 'edit', 'delete'):
if instance is None:
raise Exception("Resolving {} URL requires specifying an instance".format(action))
# Attempt to resolve using slug first
if hasattr(self.model, 'slug'):
try:
return reverse(url_format.format(action), kwargs={'slug': instance.slug})
except NoReverseMatch:
pass
return reverse(url_format.format(action), kwargs={'pk': instance.pk})
else:
raise Exception("Invalid action for URL resolution: {}".format(action))
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_list_objects(self):
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.get(self._get_url('list')), 403)
# Assign the required permission and submit again
self.add_permissions(
'{}.view_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.get(self._get_url('list'))
self.assertHttpStatus(response, 200)
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_get_object(self):
instance = self.model.objects.first()
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.get(instance.get_absolute_url()), 403)
# Assign the required permission and submit again
self.add_permissions(
'{}.view_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.get(instance.get_absolute_url())
self.assertHttpStatus(response, 200)
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_create_object(self):
initial_count = self.model.objects.count()
request = {
'path': self._get_url('add'),
'data': post_data(self.form_data),
'follow': False, # Do not follow 302 redirects
}
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.post(**request), 403)
# Assign the required permission and submit again
self.add_permissions(
'{}.add_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.post(**request)
self.assertHttpStatus(response, 302)
self.assertEqual(initial_count + 1, self.model.objects.count())
instance = self.model.objects.order_by('-pk').first()
self.assertDictEqual(model_to_dict(instance), self.form_data)
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_edit_object(self):
instance = self.model.objects.first()
request = {
'path': self._get_url('edit', instance),
'data': post_data(self.form_data),
'follow': False, # Do not follow 302 redirects
}
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.post(**request), 403)
# Assign the required permission and submit again
self.add_permissions(
'{}.change_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.post(**request)
self.assertHttpStatus(response, 302)
instance = self.model.objects.get(pk=instance.pk)
self.assertDictEqual(model_to_dict(instance), self.form_data)
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_delete_object(self):
instance = self.model.objects.first()
request = {
'path': self._get_url('delete', instance),
'data': {'confirm': True},
'follow': False, # Do not follow 302 redirects
}
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.post(**request), 403)
# Assign the required permission and submit again
self.add_permissions(
'{}.delete_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.post(**request)
self.assertHttpStatus(response, 302)
with self.assertRaises(ObjectDoesNotExist):
self.model.objects.get(pk=instance.pk)
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
def test_import_objects(self):
initial_count = self.model.objects.count()
request = {
'path': self._get_url('import'),
'data': {
'csv': '\n'.join(self.csv_data)
}
}
# Attempt to make the request without required permissions
with disable_warnings('django.request'):
self.assertHttpStatus(self.client.post(**request), 403)
# Assign the required permission and submit again
self.add_permissions(
'{}.view_{}'.format(self.model._meta.app_label, self.model._meta.model_name),
'{}.add_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
)
response = self.client.post(**request)
self.assertHttpStatus(response, 200)
self.assertEqual(self.model.objects.count(), initial_count + len(self.csv_data) - 1)

View File

@ -0,0 +1,102 @@
import logging
from contextlib import contextmanager
from django.contrib.auth.models import Permission, User
from django.forms.models import model_to_dict as _model_to_dict
def model_to_dict(instance, fields=None, exclude=None):
"""
Customized wrapper for Django's built-in model_to_dict(). Does the following:
- Excludes the instance ID field
- Exclude any fields prepended with an underscore
- Convert any assigned tags to a comma-separated string
"""
_exclude = ['id']
if exclude is not None:
_exclude += exclude
model_dict = _model_to_dict(instance, fields=fields, exclude=_exclude)
for key in list(model_dict.keys()):
if key.startswith('_'):
del model_dict[key]
# TODO: Differentiate between tags assigned to the instance and a M2M field for tags (ex: ConfigContext)
elif key == 'tags':
model_dict[key] = ','.join(sorted([tag.name for tag in model_dict['tags']]))
# Convert ManyToManyField to list of instance PKs
elif model_dict[key] and type(model_dict[key]) in (list, tuple) and hasattr(model_dict[key][0], 'pk'):
model_dict[key] = [obj.pk for obj in model_dict[key]]
return model_dict
def post_data(data):
"""
Take a dictionary of test data (suitable for comparison to an instance) and return a dict suitable for POSTing.
"""
ret = {}
for key, value in data.items():
if value is None:
ret[key] = ''
elif type(value) in (list, tuple):
ret[key] = value
else:
ret[key] = str(value)
return ret
def create_test_user(username='testuser', permissions=list()):
"""
Create a User with the given permissions.
"""
user = User.objects.create_user(username=username)
for perm_name in permissions:
app, codename = perm_name.split('.')
perm = Permission.objects.get(content_type__app_label=app, codename=codename)
user.user_permissions.add(perm)
return user
def choices_to_dict(choices_list):
"""
Convert a list of field choices to a dictionary suitable for direct comparison with a ChoiceSet. For example:
[
{
"value": "choice-1",
"label": "First Choice"
},
{
"value": "choice-2",
"label": "Second Choice"
}
]
Becomes:
{
"choice-1": "First Choice",
"choice-2": "Second Choice
}
"""
return {
choice['value']: choice['label'] for choice in choices_list
}
@contextmanager
def disable_warnings(logger_name):
"""
Temporarily suppress expected warning messages to keep the test output clean.
"""
logger = logging.getLogger(logger_name)
current_level = logger.level
logger.setLevel(logging.ERROR)
yield
logger.setLevel(current_level)

View File

@ -1,23 +1,18 @@
import urllib.parse from dcim.models import DeviceRole, Platform, Site
from utilities.testing import StandardTestCases
from django.test import Client, TestCase from virtualization.choices import *
from django.urls import reverse
from utilities.testing import create_test_user
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
class ClusterGroupTestCase(TestCase): class ClusterGroupTestCase(StandardTestCases.Views):
model = ClusterGroup
def setUp(self): # Disable inapplicable tests
user = create_test_user( test_get_object = None
permissions=[ test_delete_object = None
'virtualization.view_clustergroup',
'virtualization.add_clustergroup', @classmethod
] def setUpTestData(cls):
)
self.client = Client()
self.client.force_login(user)
ClusterGroup.objects.bulk_create([ ClusterGroup.objects.bulk_create([
ClusterGroup(name='Cluster Group 1', slug='cluster-group-1'), ClusterGroup(name='Cluster Group 1', slug='cluster-group-1'),
@ -25,39 +20,28 @@ class ClusterGroupTestCase(TestCase):
ClusterGroup(name='Cluster Group 3', slug='cluster-group-3'), ClusterGroup(name='Cluster Group 3', slug='cluster-group-3'),
]) ])
def test_clustergroup_list(self): cls.form_data = {
'name': 'Cluster Group X',
'slug': 'cluster-group-x',
}
url = reverse('virtualization:clustergroup_list') cls.csv_data = (
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_clustergroup_import(self):
csv_data = (
"name,slug", "name,slug",
"Cluster Group 4,cluster-group-4", "Cluster Group 4,cluster-group-4",
"Cluster Group 5,cluster-group-5", "Cluster Group 5,cluster-group-5",
"Cluster Group 6,cluster-group-6", "Cluster Group 6,cluster-group-6",
) )
response = self.client.post(reverse('virtualization:clustergroup_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class ClusterTypeTestCase(StandardTestCases.Views):
self.assertEqual(ClusterGroup.objects.count(), 6) model = ClusterType
# Disable inapplicable tests
test_get_object = None
test_delete_object = None
class ClusterTypeTestCase(TestCase): @classmethod
def setUpTestData(cls):
def setUp(self):
user = create_test_user(
permissions=[
'virtualization.view_clustertype',
'virtualization.add_clustertype',
]
)
self.client = Client()
self.client.force_login(user)
ClusterType.objects.bulk_create([ ClusterType.objects.bulk_create([
ClusterType(name='Cluster Type 1', slug='cluster-type-1'), ClusterType(name='Cluster Type 1', slug='cluster-type-1'),
@ -65,45 +49,28 @@ class ClusterTypeTestCase(TestCase):
ClusterType(name='Cluster Type 3', slug='cluster-type-3'), ClusterType(name='Cluster Type 3', slug='cluster-type-3'),
]) ])
def test_clustertype_list(self): cls.form_data = {
'name': 'Cluster Type X',
'slug': 'cluster-type-x',
}
url = reverse('virtualization:clustertype_list') cls.csv_data = (
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_clustertype_import(self):
csv_data = (
"name,slug", "name,slug",
"Cluster Type 4,cluster-type-4", "Cluster Type 4,cluster-type-4",
"Cluster Type 5,cluster-type-5", "Cluster Type 5,cluster-type-5",
"Cluster Type 6,cluster-type-6", "Cluster Type 6,cluster-type-6",
) )
response = self.client.post(reverse('virtualization:clustertype_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class ClusterTestCase(StandardTestCases.Views):
self.assertEqual(ClusterType.objects.count(), 6) model = Cluster
@classmethod
def setUpTestData(cls):
class ClusterTestCase(TestCase): site = Site.objects.create(name='Site 1', slug='site-1')
clustergroup = ClusterGroup.objects.create(name='Cluster Group 1', slug='cluster-group-1')
def setUp(self): clustertype = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
user = create_test_user(
permissions=[
'virtualization.view_cluster',
'virtualization.add_cluster',
]
)
self.client = Client()
self.client.force_login(user)
clustergroup = ClusterGroup(name='Cluster Group 1', slug='cluster-group-1')
clustergroup.save()
clustertype = ClusterType(name='Cluster Type 1', slug='cluster-type-1')
clustertype.save()
Cluster.objects.bulk_create([ Cluster.objects.bulk_create([
Cluster(name='Cluster 1', group=clustergroup, type=clustertype), Cluster(name='Cluster 1', group=clustergroup, type=clustertype),
@ -111,55 +78,34 @@ class ClusterTestCase(TestCase):
Cluster(name='Cluster 3', group=clustergroup, type=clustertype), Cluster(name='Cluster 3', group=clustergroup, type=clustertype),
]) ])
def test_cluster_list(self): cls.form_data = {
'name': 'Cluster X',
url = reverse('virtualization:cluster_list') 'group': clustergroup.pk,
params = { 'type': clustertype.pk,
"group": ClusterGroup.objects.first().slug, 'tenant': None,
"type": ClusterType.objects.first().slug, 'site': site.pk,
'comments': 'Some comments',
'tags': 'Alpha,Bravo,Charlie',
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_cluster(self):
cluster = Cluster.objects.first()
response = self.client.get(cluster.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_cluster_import(self):
csv_data = (
"name,type", "name,type",
"Cluster 4,Cluster Type 1", "Cluster 4,Cluster Type 1",
"Cluster 5,Cluster Type 1", "Cluster 5,Cluster Type 1",
"Cluster 6,Cluster Type 1", "Cluster 6,Cluster Type 1",
) )
response = self.client.post(reverse('virtualization:cluster_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200) class VirtualMachineTestCase(StandardTestCases.Views):
self.assertEqual(Cluster.objects.count(), 6) model = VirtualMachine
@classmethod
def setUpTestData(cls):
class VirtualMachineTestCase(TestCase): devicerole = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
platform = Platform.objects.create(name='Platform 1', slug='platform-1')
def setUp(self): clustertype = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
user = create_test_user( cluster = Cluster.objects.create(name='Cluster 1', type=clustertype)
permissions=[
'virtualization.view_virtualmachine',
'virtualization.add_virtualmachine',
]
)
self.client = Client()
self.client.force_login(user)
clustertype = ClusterType(name='Cluster Type 1', slug='cluster-type-1')
clustertype.save()
cluster = Cluster(name='Cluster 1', type=clustertype)
cluster.save()
VirtualMachine.objects.bulk_create([ VirtualMachine.objects.bulk_create([
VirtualMachine(name='Virtual Machine 1', cluster=cluster), VirtualMachine(name='Virtual Machine 1', cluster=cluster),
@ -167,32 +113,26 @@ class VirtualMachineTestCase(TestCase):
VirtualMachine(name='Virtual Machine 3', cluster=cluster), VirtualMachine(name='Virtual Machine 3', cluster=cluster),
]) ])
def test_virtualmachine_list(self): cls.form_data = {
'cluster': cluster.pk,
url = reverse('virtualization:virtualmachine_list') 'tenant': None,
params = { 'platform': None,
"cluster_id": Cluster.objects.first().pk, 'name': 'Virtual Machine X',
'status': VirtualMachineStatusChoices.STATUS_STAGED,
'role': devicerole.pk,
'primary_ip4': None,
'primary_ip6': None,
'vcpus': 4,
'memory': 32768,
'disk': 4000,
'comments': 'Some comments',
'tags': 'Alpha,Bravo,Charlie',
'local_context_data': None,
} }
response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params))) cls.csv_data = (
self.assertEqual(response.status_code, 200)
def test_virtualmachine(self):
virtualmachine = VirtualMachine.objects.first()
response = self.client.get(virtualmachine.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_virtualmachine_import(self):
csv_data = (
"name,cluster", "name,cluster",
"Virtual Machine 4,Cluster 1", "Virtual Machine 4,Cluster 1",
"Virtual Machine 5,Cluster 1", "Virtual Machine 5,Cluster 1",
"Virtual Machine 6,Cluster 1", "Virtual Machine 6,Cluster 1",
) )
response = self.client.post(reverse('virtualization:virtualmachine_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200)
self.assertEqual(VirtualMachine.objects.count(), 6)