1from netaddr import IPNetwork, IPSet
2from django.core.exceptions import ValidationError
3from django.test import TestCase, override_settings
4
5from ipam.choices import IPAddressRoleChoices, PrefixStatusChoices
6from ipam.models import Aggregate, IPAddress, IPRange, Prefix, RIR, VLAN, VLANGroup, VRF
7
8
9class TestAggregate(TestCase):
10
11    def test_get_utilization(self):
12        rir = RIR.objects.create(name='RIR 1', slug='rir-1')
13        aggregate = Aggregate(prefix=IPNetwork('10.0.0.0/8'), rir=rir)
14        aggregate.save()
15
16        # 25% utilization
17        Prefix.objects.bulk_create((
18            Prefix(prefix=IPNetwork('10.0.0.0/12')),
19            Prefix(prefix=IPNetwork('10.16.0.0/12')),
20            Prefix(prefix=IPNetwork('10.32.0.0/12')),
21            Prefix(prefix=IPNetwork('10.48.0.0/12')),
22        ))
23        self.assertEqual(aggregate.get_utilization(), 25)
24
25        # 50% utilization
26        Prefix.objects.bulk_create((
27            Prefix(prefix=IPNetwork('10.64.0.0/10')),
28        ))
29        self.assertEqual(aggregate.get_utilization(), 50)
30
31        # 100% utilization
32        Prefix.objects.bulk_create((
33            Prefix(prefix=IPNetwork('10.128.0.0/9')),
34        ))
35        self.assertEqual(aggregate.get_utilization(), 100)
36
37
38class TestPrefix(TestCase):
39
40    def test_get_duplicates(self):
41        prefixes = Prefix.objects.bulk_create((
42            Prefix(prefix=IPNetwork('192.0.2.0/24')),
43            Prefix(prefix=IPNetwork('192.0.2.0/24')),
44            Prefix(prefix=IPNetwork('192.0.2.0/24')),
45        ))
46        duplicate_prefix_pks = [p.pk for p in prefixes[0].get_duplicates()]
47
48        self.assertSetEqual(set(duplicate_prefix_pks), {prefixes[1].pk, prefixes[2].pk})
49
50    def test_get_child_prefixes(self):
51        vrfs = VRF.objects.bulk_create((
52            VRF(name='VRF 1'),
53            VRF(name='VRF 2'),
54            VRF(name='VRF 3'),
55        ))
56        prefixes = Prefix.objects.bulk_create((
57            Prefix(prefix=IPNetwork('10.0.0.0/16'), status=PrefixStatusChoices.STATUS_CONTAINER),
58            Prefix(prefix=IPNetwork('10.0.0.0/24'), vrf=None),
59            Prefix(prefix=IPNetwork('10.0.1.0/24'), vrf=vrfs[0]),
60            Prefix(prefix=IPNetwork('10.0.2.0/24'), vrf=vrfs[1]),
61            Prefix(prefix=IPNetwork('10.0.3.0/24'), vrf=vrfs[2]),
62        ))
63        child_prefix_pks = {p.pk for p in prefixes[0].get_child_prefixes()}
64
65        # Global container should return all children
66        self.assertSetEqual(child_prefix_pks, {prefixes[1].pk, prefixes[2].pk, prefixes[3].pk, prefixes[4].pk})
67
68        prefixes[0].vrf = vrfs[0]
69        prefixes[0].save()
70        child_prefix_pks = {p.pk for p in prefixes[0].get_child_prefixes()}
71
72        # VRF container is limited to its own VRF
73        self.assertSetEqual(child_prefix_pks, {prefixes[2].pk})
74
75    def test_get_child_ranges(self):
76        prefix = Prefix(prefix='192.168.0.16/28')
77        prefix.save()
78        ranges = IPRange.objects.bulk_create((
79            IPRange(start_address=IPNetwork('192.168.0.1/24'), end_address=IPNetwork('192.168.0.10/24'), size=10),  # No overlap
80            IPRange(start_address=IPNetwork('192.168.0.11/24'), end_address=IPNetwork('192.168.0.17/24'), size=7),  # Partial overlap
81            IPRange(start_address=IPNetwork('192.168.0.18/24'), end_address=IPNetwork('192.168.0.23/24'), size=6),  # Full overlap
82            IPRange(start_address=IPNetwork('192.168.0.24/24'), end_address=IPNetwork('192.168.0.30/24'), size=7),  # Full overlap
83            IPRange(start_address=IPNetwork('192.168.0.31/24'), end_address=IPNetwork('192.168.0.40/24'), size=10),  # Partial overlap
84        ))
85
86        child_ranges = prefix.get_child_ranges()
87
88        self.assertEqual(len(child_ranges), 2)
89        self.assertEqual(child_ranges[0], ranges[2])
90        self.assertEqual(child_ranges[1], ranges[3])
91
92    def test_get_child_ips(self):
93        vrfs = VRF.objects.bulk_create((
94            VRF(name='VRF 1'),
95            VRF(name='VRF 2'),
96            VRF(name='VRF 3'),
97        ))
98        parent_prefix = Prefix.objects.create(
99            prefix=IPNetwork('10.0.0.0/16'), status=PrefixStatusChoices.STATUS_CONTAINER
100        )
101        ips = IPAddress.objects.bulk_create((
102            IPAddress(address=IPNetwork('10.0.0.1/24'), vrf=None),
103            IPAddress(address=IPNetwork('10.0.1.1/24'), vrf=vrfs[0]),
104            IPAddress(address=IPNetwork('10.0.2.1/24'), vrf=vrfs[1]),
105            IPAddress(address=IPNetwork('10.0.3.1/24'), vrf=vrfs[2]),
106        ))
107        child_ip_pks = {p.pk for p in parent_prefix.get_child_ips()}
108
109        # Global container should return all children
110        self.assertSetEqual(child_ip_pks, {ips[0].pk, ips[1].pk, ips[2].pk, ips[3].pk})
111
112        parent_prefix.vrf = vrfs[0]
113        parent_prefix.save()
114        child_ip_pks = {p.pk for p in parent_prefix.get_child_ips()}
115
116        # VRF container is limited to its own VRF
117        self.assertSetEqual(child_ip_pks, {ips[1].pk})
118
119    def test_get_available_prefixes(self):
120
121        prefixes = Prefix.objects.bulk_create((
122            Prefix(prefix=IPNetwork('10.0.0.0/16')),  # Parent prefix
123            Prefix(prefix=IPNetwork('10.0.0.0/20')),
124            Prefix(prefix=IPNetwork('10.0.32.0/20')),
125            Prefix(prefix=IPNetwork('10.0.128.0/18')),
126        ))
127        missing_prefixes = IPSet([
128            IPNetwork('10.0.16.0/20'),
129            IPNetwork('10.0.48.0/20'),
130            IPNetwork('10.0.64.0/18'),
131            IPNetwork('10.0.192.0/18'),
132        ])
133        available_prefixes = prefixes[0].get_available_prefixes()
134
135        self.assertEqual(available_prefixes, missing_prefixes)
136
137    def test_get_available_ips(self):
138
139        parent_prefix = Prefix.objects.create(prefix=IPNetwork('10.0.0.0/28'))
140        IPAddress.objects.bulk_create((
141            IPAddress(address=IPNetwork('10.0.0.1/26')),
142            IPAddress(address=IPNetwork('10.0.0.3/26')),
143            IPAddress(address=IPNetwork('10.0.0.5/26')),
144            IPAddress(address=IPNetwork('10.0.0.7/26')),
145        ))
146        IPRange.objects.create(
147            start_address=IPNetwork('10.0.0.9/26'),
148            end_address=IPNetwork('10.0.0.12/26')
149        )
150        missing_ips = IPSet([
151            '10.0.0.2/32',
152            '10.0.0.4/32',
153            '10.0.0.6/32',
154            '10.0.0.8/32',
155            '10.0.0.13/32',
156            '10.0.0.14/32',
157        ])
158        available_ips = parent_prefix.get_available_ips()
159
160        self.assertEqual(available_ips, missing_ips)
161
162    def test_get_first_available_prefix(self):
163
164        prefixes = Prefix.objects.bulk_create((
165            Prefix(prefix=IPNetwork('10.0.0.0/16')),  # Parent prefix
166            Prefix(prefix=IPNetwork('10.0.0.0/24')),
167            Prefix(prefix=IPNetwork('10.0.1.0/24')),
168            Prefix(prefix=IPNetwork('10.0.2.0/24')),
169        ))
170        self.assertEqual(prefixes[0].get_first_available_prefix(), IPNetwork('10.0.3.0/24'))
171
172        Prefix.objects.create(prefix=IPNetwork('10.0.3.0/24'))
173        self.assertEqual(prefixes[0].get_first_available_prefix(), IPNetwork('10.0.4.0/22'))
174
175    def test_get_first_available_ip(self):
176
177        parent_prefix = Prefix.objects.create(prefix=IPNetwork('10.0.0.0/24'))
178        IPAddress.objects.bulk_create((
179            IPAddress(address=IPNetwork('10.0.0.1/24')),
180            IPAddress(address=IPNetwork('10.0.0.2/24')),
181            IPAddress(address=IPNetwork('10.0.0.3/24')),
182        ))
183        self.assertEqual(parent_prefix.get_first_available_ip(), '10.0.0.4/24')
184
185        IPAddress.objects.create(address=IPNetwork('10.0.0.4/24'))
186        self.assertEqual(parent_prefix.get_first_available_ip(), '10.0.0.5/24')
187
188    def test_get_utilization_container(self):
189        prefixes = (
190            Prefix(prefix=IPNetwork('10.0.0.0/24'), status=PrefixStatusChoices.STATUS_CONTAINER),
191            Prefix(prefix=IPNetwork('10.0.0.0/26')),
192            Prefix(prefix=IPNetwork('10.0.0.128/26')),
193        )
194        Prefix.objects.bulk_create(prefixes)
195        self.assertEqual(prefixes[0].get_utilization(), 50)  # 50% utilization
196
197    def test_get_utilization_noncontainer(self):
198        prefix = Prefix.objects.create(
199            prefix=IPNetwork('10.0.0.0/24'),
200            status=PrefixStatusChoices.STATUS_ACTIVE
201        )
202
203        # Create 32 child IPs
204        IPAddress.objects.bulk_create([
205            IPAddress(address=IPNetwork(f'10.0.0.{i}/24')) for i in range(1, 33)
206        ])
207        self.assertEqual(prefix.get_utilization(), 12)  # 12.5% utilization
208
209        # Create a child range with 32 additional IPs
210        IPRange.objects.create(start_address=IPNetwork('10.0.0.33/24'), end_address=IPNetwork('10.0.0.64/24'))
211        self.assertEqual(prefix.get_utilization(), 25)  # 25% utilization
212
213    #
214    # Uniqueness enforcement tests
215    #
216
217    @override_settings(ENFORCE_GLOBAL_UNIQUE=False)
218    def test_duplicate_global(self):
219        Prefix.objects.create(prefix=IPNetwork('192.0.2.0/24'))
220        duplicate_prefix = Prefix(prefix=IPNetwork('192.0.2.0/24'))
221        self.assertIsNone(duplicate_prefix.clean())
222
223    @override_settings(ENFORCE_GLOBAL_UNIQUE=True)
224    def test_duplicate_global_unique(self):
225        Prefix.objects.create(prefix=IPNetwork('192.0.2.0/24'))
226        duplicate_prefix = Prefix(prefix=IPNetwork('192.0.2.0/24'))
227        self.assertRaises(ValidationError, duplicate_prefix.clean)
228
229    def test_duplicate_vrf(self):
230        vrf = VRF.objects.create(name='Test', rd='1:1', enforce_unique=False)
231        Prefix.objects.create(vrf=vrf, prefix=IPNetwork('192.0.2.0/24'))
232        duplicate_prefix = Prefix(vrf=vrf, prefix=IPNetwork('192.0.2.0/24'))
233        self.assertIsNone(duplicate_prefix.clean())
234
235    def test_duplicate_vrf_unique(self):
236        vrf = VRF.objects.create(name='Test', rd='1:1', enforce_unique=True)
237        Prefix.objects.create(vrf=vrf, prefix=IPNetwork('192.0.2.0/24'))
238        duplicate_prefix = Prefix(vrf=vrf, prefix=IPNetwork('192.0.2.0/24'))
239        self.assertRaises(ValidationError, duplicate_prefix.clean)
240
241
242class TestPrefixHierarchy(TestCase):
243    """
244    Test the automatic updating of depth and child count in response to changes made within
245    the prefix hierarchy.
246    """
247    @classmethod
248    def setUpTestData(cls):
249
250        prefixes = (
251
252            # IPv4
253            Prefix(prefix='10.0.0.0/8', _depth=0, _children=2),
254            Prefix(prefix='10.0.0.0/16', _depth=1, _children=1),
255            Prefix(prefix='10.0.0.0/24', _depth=2, _children=0),
256
257            # IPv6
258            Prefix(prefix='2001:db8::/32', _depth=0, _children=2),
259            Prefix(prefix='2001:db8::/40', _depth=1, _children=1),
260            Prefix(prefix='2001:db8::/48', _depth=2, _children=0),
261
262        )
263        Prefix.objects.bulk_create(prefixes)
264
265    def test_create_prefix4(self):
266        # Create 10.0.0.0/12
267        Prefix(prefix='10.0.0.0/12').save()
268
269        prefixes = Prefix.objects.filter(prefix__family=4)
270        self.assertEqual(prefixes[0].prefix, IPNetwork('10.0.0.0/8'))
271        self.assertEqual(prefixes[0]._depth, 0)
272        self.assertEqual(prefixes[0]._children, 3)
273        self.assertEqual(prefixes[1].prefix, IPNetwork('10.0.0.0/12'))
274        self.assertEqual(prefixes[1]._depth, 1)
275        self.assertEqual(prefixes[1]._children, 2)
276        self.assertEqual(prefixes[2].prefix, IPNetwork('10.0.0.0/16'))
277        self.assertEqual(prefixes[2]._depth, 2)
278        self.assertEqual(prefixes[2]._children, 1)
279        self.assertEqual(prefixes[3].prefix, IPNetwork('10.0.0.0/24'))
280        self.assertEqual(prefixes[3]._depth, 3)
281        self.assertEqual(prefixes[3]._children, 0)
282
283    def test_create_prefix6(self):
284        # Create 2001:db8::/36
285        Prefix(prefix='2001:db8::/36').save()
286
287        prefixes = Prefix.objects.filter(prefix__family=6)
288        self.assertEqual(prefixes[0].prefix, IPNetwork('2001:db8::/32'))
289        self.assertEqual(prefixes[0]._depth, 0)
290        self.assertEqual(prefixes[0]._children, 3)
291        self.assertEqual(prefixes[1].prefix, IPNetwork('2001:db8::/36'))
292        self.assertEqual(prefixes[1]._depth, 1)
293        self.assertEqual(prefixes[1]._children, 2)
294        self.assertEqual(prefixes[2].prefix, IPNetwork('2001:db8::/40'))
295        self.assertEqual(prefixes[2]._depth, 2)
296        self.assertEqual(prefixes[2]._children, 1)
297        self.assertEqual(prefixes[3].prefix, IPNetwork('2001:db8::/48'))
298        self.assertEqual(prefixes[3]._depth, 3)
299        self.assertEqual(prefixes[3]._children, 0)
300
301    def test_update_prefix4(self):
302        # Change 10.0.0.0/24 to 10.0.0.0/12
303        p = Prefix.objects.get(prefix='10.0.0.0/24')
304        p.prefix = '10.0.0.0/12'
305        p.save()
306
307        prefixes = Prefix.objects.filter(prefix__family=4)
308        self.assertEqual(prefixes[0].prefix, IPNetwork('10.0.0.0/8'))
309        self.assertEqual(prefixes[0]._depth, 0)
310        self.assertEqual(prefixes[0]._children, 2)
311        self.assertEqual(prefixes[1].prefix, IPNetwork('10.0.0.0/12'))
312        self.assertEqual(prefixes[1]._depth, 1)
313        self.assertEqual(prefixes[1]._children, 1)
314        self.assertEqual(prefixes[2].prefix, IPNetwork('10.0.0.0/16'))
315        self.assertEqual(prefixes[2]._depth, 2)
316        self.assertEqual(prefixes[2]._children, 0)
317
318    def test_update_prefix6(self):
319        # Change 2001:db8::/48 to 2001:db8::/36
320        p = Prefix.objects.get(prefix='2001:db8::/48')
321        p.prefix = '2001:db8::/36'
322        p.save()
323
324        prefixes = Prefix.objects.filter(prefix__family=6)
325        self.assertEqual(prefixes[0].prefix, IPNetwork('2001:db8::/32'))
326        self.assertEqual(prefixes[0]._depth, 0)
327        self.assertEqual(prefixes[0]._children, 2)
328        self.assertEqual(prefixes[1].prefix, IPNetwork('2001:db8::/36'))
329        self.assertEqual(prefixes[1]._depth, 1)
330        self.assertEqual(prefixes[1]._children, 1)
331        self.assertEqual(prefixes[2].prefix, IPNetwork('2001:db8::/40'))
332        self.assertEqual(prefixes[2]._depth, 2)
333        self.assertEqual(prefixes[2]._children, 0)
334
335    def test_update_prefix_vrf4(self):
336        vrf = VRF(name='VRF A')
337        vrf.save()
338
339        # Move 10.0.0.0/16 to a VRF
340        p = Prefix.objects.get(prefix='10.0.0.0/16')
341        p.vrf = vrf
342        p.save()
343
344        prefixes = Prefix.objects.filter(vrf__isnull=True, prefix__family=4)
345        self.assertEqual(prefixes[0].prefix, IPNetwork('10.0.0.0/8'))
346        self.assertEqual(prefixes[0]._depth, 0)
347        self.assertEqual(prefixes[0]._children, 1)
348        self.assertEqual(prefixes[1].prefix, IPNetwork('10.0.0.0/24'))
349        self.assertEqual(prefixes[1]._depth, 1)
350        self.assertEqual(prefixes[1]._children, 0)
351
352        prefixes = Prefix.objects.filter(vrf=vrf)
353        self.assertEqual(prefixes[0].prefix, IPNetwork('10.0.0.0/16'))
354        self.assertEqual(prefixes[0]._depth, 0)
355        self.assertEqual(prefixes[0]._children, 0)
356
357    def test_update_prefix_vrf6(self):
358        vrf = VRF(name='VRF A')
359        vrf.save()
360
361        # Move 2001:db8::/40 to a VRF
362        p = Prefix.objects.get(prefix='2001:db8::/40')
363        p.vrf = vrf
364        p.save()
365
366        prefixes = Prefix.objects.filter(vrf__isnull=True, prefix__family=6)
367        self.assertEqual(prefixes[0].prefix, IPNetwork('2001:db8::/32'))
368        self.assertEqual(prefixes[0]._depth, 0)
369        self.assertEqual(prefixes[0]._children, 1)
370        self.assertEqual(prefixes[1].prefix, IPNetwork('2001:db8::/48'))
371        self.assertEqual(prefixes[1]._depth, 1)
372        self.assertEqual(prefixes[1]._children, 0)
373
374        prefixes = Prefix.objects.filter(vrf=vrf)
375        self.assertEqual(prefixes[0].prefix, IPNetwork('2001:db8::/40'))
376        self.assertEqual(prefixes[0]._depth, 0)
377        self.assertEqual(prefixes[0]._children, 0)
378
379    def test_delete_prefix4(self):
380        # Delete 10.0.0.0/16
381        Prefix.objects.filter(prefix='10.0.0.0/16').delete()
382
383        prefixes = Prefix.objects.filter(prefix__family=4)
384        self.assertEqual(prefixes[0].prefix, IPNetwork('10.0.0.0/8'))
385        self.assertEqual(prefixes[0]._depth, 0)
386        self.assertEqual(prefixes[0]._children, 1)
387        self.assertEqual(prefixes[1].prefix, IPNetwork('10.0.0.0/24'))
388        self.assertEqual(prefixes[1]._depth, 1)
389        self.assertEqual(prefixes[1]._children, 0)
390
391    def test_delete_prefix6(self):
392        # Delete 2001:db8::/40
393        Prefix.objects.filter(prefix='2001:db8::/40').delete()
394
395        prefixes = Prefix.objects.filter(prefix__family=6)
396        self.assertEqual(prefixes[0].prefix, IPNetwork('2001:db8::/32'))
397        self.assertEqual(prefixes[0]._depth, 0)
398        self.assertEqual(prefixes[0]._children, 1)
399        self.assertEqual(prefixes[1].prefix, IPNetwork('2001:db8::/48'))
400        self.assertEqual(prefixes[1]._depth, 1)
401        self.assertEqual(prefixes[1]._children, 0)
402
403    def test_duplicate_prefix4(self):
404        # Duplicate 10.0.0.0/16
405        Prefix(prefix='10.0.0.0/16').save()
406
407        prefixes = Prefix.objects.filter(prefix__family=4)
408        self.assertEqual(prefixes[0].prefix, IPNetwork('10.0.0.0/8'))
409        self.assertEqual(prefixes[0]._depth, 0)
410        self.assertEqual(prefixes[0]._children, 3)
411        self.assertEqual(prefixes[1].prefix, IPNetwork('10.0.0.0/16'))
412        self.assertEqual(prefixes[1]._depth, 1)
413        self.assertEqual(prefixes[1]._children, 1)
414        self.assertEqual(prefixes[2].prefix, IPNetwork('10.0.0.0/16'))
415        self.assertEqual(prefixes[2]._depth, 1)
416        self.assertEqual(prefixes[2]._children, 1)
417        self.assertEqual(prefixes[3].prefix, IPNetwork('10.0.0.0/24'))
418        self.assertEqual(prefixes[3]._depth, 2)
419        self.assertEqual(prefixes[3]._children, 0)
420
421    def test_duplicate_prefix6(self):
422        # Duplicate 2001:db8::/40
423        Prefix(prefix='2001:db8::/40').save()
424
425        prefixes = Prefix.objects.filter(prefix__family=6)
426        self.assertEqual(prefixes[0].prefix, IPNetwork('2001:db8::/32'))
427        self.assertEqual(prefixes[0]._depth, 0)
428        self.assertEqual(prefixes[0]._children, 3)
429        self.assertEqual(prefixes[1].prefix, IPNetwork('2001:db8::/40'))
430        self.assertEqual(prefixes[1]._depth, 1)
431        self.assertEqual(prefixes[1]._children, 1)
432        self.assertEqual(prefixes[2].prefix, IPNetwork('2001:db8::/40'))
433        self.assertEqual(prefixes[2]._depth, 1)
434        self.assertEqual(prefixes[2]._children, 1)
435        self.assertEqual(prefixes[3].prefix, IPNetwork('2001:db8::/48'))
436        self.assertEqual(prefixes[3]._depth, 2)
437        self.assertEqual(prefixes[3]._children, 0)
438
439
440class TestIPAddress(TestCase):
441
442    def test_get_duplicates(self):
443        ips = IPAddress.objects.bulk_create((
444            IPAddress(address=IPNetwork('192.0.2.1/24')),
445            IPAddress(address=IPNetwork('192.0.2.1/24')),
446            IPAddress(address=IPNetwork('192.0.2.1/24')),
447        ))
448        duplicate_ip_pks = [p.pk for p in ips[0].get_duplicates()]
449
450        self.assertSetEqual(set(duplicate_ip_pks), {ips[1].pk, ips[2].pk})
451
452    #
453    # Uniqueness enforcement tests
454    #
455
456    @override_settings(ENFORCE_GLOBAL_UNIQUE=False)
457    def test_duplicate_global(self):
458        IPAddress.objects.create(address=IPNetwork('192.0.2.1/24'))
459        duplicate_ip = IPAddress(address=IPNetwork('192.0.2.1/24'))
460        self.assertIsNone(duplicate_ip.clean())
461
462    @override_settings(ENFORCE_GLOBAL_UNIQUE=True)
463    def test_duplicate_global_unique(self):
464        IPAddress.objects.create(address=IPNetwork('192.0.2.1/24'))
465        duplicate_ip = IPAddress(address=IPNetwork('192.0.2.1/24'))
466        self.assertRaises(ValidationError, duplicate_ip.clean)
467
468    def test_duplicate_vrf(self):
469        vrf = VRF.objects.create(name='Test', rd='1:1', enforce_unique=False)
470        IPAddress.objects.create(vrf=vrf, address=IPNetwork('192.0.2.1/24'))
471        duplicate_ip = IPAddress(vrf=vrf, address=IPNetwork('192.0.2.1/24'))
472        self.assertIsNone(duplicate_ip.clean())
473
474    def test_duplicate_vrf_unique(self):
475        vrf = VRF.objects.create(name='Test', rd='1:1', enforce_unique=True)
476        IPAddress.objects.create(vrf=vrf, address=IPNetwork('192.0.2.1/24'))
477        duplicate_ip = IPAddress(vrf=vrf, address=IPNetwork('192.0.2.1/24'))
478        self.assertRaises(ValidationError, duplicate_ip.clean)
479
480    @override_settings(ENFORCE_GLOBAL_UNIQUE=True)
481    def test_duplicate_nonunique_nonrole_role(self):
482        IPAddress.objects.create(address=IPNetwork('192.0.2.1/24'))
483        duplicate_ip = IPAddress(address=IPNetwork('192.0.2.1/24'), role=IPAddressRoleChoices.ROLE_VIP)
484        self.assertRaises(ValidationError, duplicate_ip.clean)
485
486    @override_settings(ENFORCE_GLOBAL_UNIQUE=True)
487    def test_duplicate_nonunique_role_nonrole(self):
488        IPAddress.objects.create(address=IPNetwork('192.0.2.1/24'), role=IPAddressRoleChoices.ROLE_VIP)
489        duplicate_ip = IPAddress(address=IPNetwork('192.0.2.1/24'))
490        self.assertRaises(ValidationError, duplicate_ip.clean)
491
492    @override_settings(ENFORCE_GLOBAL_UNIQUE=True)
493    def test_duplicate_nonunique_role(self):
494        IPAddress.objects.create(address=IPNetwork('192.0.2.1/24'), role=IPAddressRoleChoices.ROLE_VIP)
495        IPAddress.objects.create(address=IPNetwork('192.0.2.1/24'), role=IPAddressRoleChoices.ROLE_VIP)
496
497
498class TestVLANGroup(TestCase):
499
500    def test_get_next_available_vid(self):
501
502        vlangroup = VLANGroup.objects.create(name='VLAN Group 1', slug='vlan-group-1')
503        VLAN.objects.bulk_create((
504            VLAN(name='VLAN 1', vid=1, group=vlangroup),
505            VLAN(name='VLAN 2', vid=2, group=vlangroup),
506            VLAN(name='VLAN 3', vid=3, group=vlangroup),
507            VLAN(name='VLAN 5', vid=5, group=vlangroup),
508        ))
509        self.assertEqual(vlangroup.get_next_available_vid(), 4)
510
511        VLAN.objects.bulk_create((
512            VLAN(name='VLAN 4', vid=4, group=vlangroup),
513        ))
514        self.assertEqual(vlangroup.get_next_available_vid(), 6)
515