mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 11:37:21 -06:00
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:
commit
ce081a6e15
@ -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)
|
|
||||||
|
@ -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
@ -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)
|
||||||
|
@ -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)
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
|
||||||
|
@ -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)
|
|
2
netbox/utilities/testing/__init__.py
Normal file
2
netbox/utilities/testing/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .testcases import *
|
||||||
|
from .utils import *
|
249
netbox/utilities/testing/testcases.py
Normal file
249
netbox/utilities/testing/testcases.py
Normal 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)
|
102
netbox/utilities/testing/utils.py
Normal file
102
netbox/utilities/testing/utils.py
Normal 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)
|
@ -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)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user