test_api.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. import json
  2. from django.urls import reverse
  3. from rest_framework import status
  4. from dcim.choices import InterfaceTypeChoices
  5. from dcim.models import Interface
  6. from ipam.models import VLAN, IPAddress
  7. from utilities.testing import APITestCase, APIViewTestCases, create_test_device
  8. from vpn.choices import *
  9. from vpn.models import *
  10. class AppTestCase(APITestCase):
  11. def test_root(self):
  12. url = reverse('vpn-api:api-root')
  13. response = self.client.get('{}?format=api'.format(url), **self.header)
  14. self.assertEqual(response.status_code, 200)
  15. class TunnelGroupTestCase(APIViewTestCases.APIViewTestCase):
  16. model = TunnelGroup
  17. brief_fields = ['description', 'display', 'id', 'name', 'slug', 'tunnel_count', 'url']
  18. create_data = (
  19. {
  20. 'name': 'Tunnel Group 4',
  21. 'slug': 'tunnel-group-4',
  22. },
  23. {
  24. 'name': 'Tunnel Group 5',
  25. 'slug': 'tunnel-group-5',
  26. },
  27. {
  28. 'name': 'Tunnel Group 6',
  29. 'slug': 'tunnel-group-6',
  30. },
  31. )
  32. bulk_update_data = {
  33. 'description': 'New description',
  34. }
  35. bulk_update_invalid_data = {
  36. 'owner': 99999,
  37. }
  38. @classmethod
  39. def setUpTestData(cls):
  40. tunnel_groups = (
  41. TunnelGroup(name='Tunnel Group 1', slug='tunnel-group-1'),
  42. TunnelGroup(name='Tunnel Group 2', slug='tunnel-group-2'),
  43. TunnelGroup(name='Tunnel Group 3', slug='tunnel-group-3'),
  44. )
  45. TunnelGroup.objects.bulk_create(tunnel_groups)
  46. class TunnelTestCase(APIViewTestCases.APIViewTestCase):
  47. model = Tunnel
  48. brief_fields = ['description', 'display', 'id', 'name', 'url']
  49. bulk_update_data = {
  50. 'status': TunnelStatusChoices.STATUS_PLANNED,
  51. 'encapsulation': TunnelEncapsulationChoices.ENCAP_GRE,
  52. 'description': 'New description',
  53. }
  54. bulk_update_invalid_data = {
  55. 'status': 'not-a-valid-status',
  56. }
  57. @classmethod
  58. def setUpTestData(cls):
  59. tunnel_groups = (
  60. TunnelGroup(name='Tunnel Group 1', slug='tunnel-group-1'),
  61. TunnelGroup(name='Tunnel Group 2', slug='tunnel-group-2'),
  62. )
  63. TunnelGroup.objects.bulk_create(tunnel_groups)
  64. tunnels = (
  65. Tunnel(
  66. name='Tunnel 1',
  67. status=TunnelStatusChoices.STATUS_ACTIVE,
  68. group=tunnel_groups[0],
  69. encapsulation=TunnelEncapsulationChoices.ENCAP_IP_IP
  70. ),
  71. Tunnel(
  72. name='Tunnel 2',
  73. status=TunnelStatusChoices.STATUS_ACTIVE,
  74. group=tunnel_groups[0],
  75. encapsulation=TunnelEncapsulationChoices.ENCAP_IP_IP
  76. ),
  77. Tunnel(
  78. name='Tunnel 3',
  79. status=TunnelStatusChoices.STATUS_ACTIVE,
  80. group=tunnel_groups[0],
  81. encapsulation=TunnelEncapsulationChoices.ENCAP_IP_IP
  82. ),
  83. )
  84. Tunnel.objects.bulk_create(tunnels)
  85. cls.create_data = [
  86. {
  87. 'name': 'Tunnel 4',
  88. 'status': TunnelStatusChoices.STATUS_DISABLED,
  89. 'group': tunnel_groups[1].pk,
  90. 'encapsulation': TunnelEncapsulationChoices.ENCAP_GRE,
  91. },
  92. {
  93. 'name': 'Tunnel 5',
  94. 'status': TunnelStatusChoices.STATUS_DISABLED,
  95. 'group': tunnel_groups[1].pk,
  96. 'encapsulation': TunnelEncapsulationChoices.ENCAP_GRE,
  97. },
  98. {
  99. 'name': 'Tunnel 6',
  100. 'status': TunnelStatusChoices.STATUS_DISABLED,
  101. 'encapsulation': TunnelEncapsulationChoices.ENCAP_GRE,
  102. },
  103. ]
  104. class TunnelTerminationTestCase(APIViewTestCases.APIViewTestCase):
  105. model = TunnelTermination
  106. brief_fields = ['display', 'id', 'url']
  107. bulk_update_data = {
  108. 'role': TunnelTerminationRoleChoices.ROLE_PEER,
  109. }
  110. bulk_update_invalid_data = {
  111. 'role': 'not-a-valid-role',
  112. }
  113. user_permissions = ('vpn.view_tunnel', )
  114. @classmethod
  115. def setUpTestData(cls):
  116. device = create_test_device('Device 1')
  117. interfaces = (
  118. Interface(device=device, name='Interface 1', type=InterfaceTypeChoices.TYPE_VIRTUAL),
  119. Interface(device=device, name='Interface 2', type=InterfaceTypeChoices.TYPE_VIRTUAL),
  120. Interface(device=device, name='Interface 3', type=InterfaceTypeChoices.TYPE_VIRTUAL),
  121. Interface(device=device, name='Interface 4', type=InterfaceTypeChoices.TYPE_VIRTUAL),
  122. Interface(device=device, name='Interface 5', type=InterfaceTypeChoices.TYPE_VIRTUAL),
  123. Interface(device=device, name='Interface 6', type=InterfaceTypeChoices.TYPE_VIRTUAL),
  124. )
  125. Interface.objects.bulk_create(interfaces)
  126. tunnel = Tunnel.objects.create(
  127. name='Tunnel 1',
  128. status=TunnelStatusChoices.STATUS_ACTIVE,
  129. encapsulation=TunnelEncapsulationChoices.ENCAP_IP_IP
  130. )
  131. tunnel_terminations = (
  132. TunnelTermination(
  133. tunnel=tunnel,
  134. role=TunnelTerminationRoleChoices.ROLE_HUB,
  135. termination=interfaces[0]
  136. ),
  137. TunnelTermination(
  138. tunnel=tunnel,
  139. role=TunnelTerminationRoleChoices.ROLE_HUB,
  140. termination=interfaces[1]
  141. ),
  142. TunnelTermination(
  143. tunnel=tunnel,
  144. role=TunnelTerminationRoleChoices.ROLE_HUB,
  145. termination=interfaces[2]
  146. ),
  147. )
  148. TunnelTermination.objects.bulk_create(tunnel_terminations)
  149. cls.create_data = [
  150. {
  151. 'tunnel': tunnel.pk,
  152. 'role': TunnelTerminationRoleChoices.ROLE_PEER,
  153. 'termination_type': 'dcim.interface',
  154. 'termination_id': interfaces[3].pk,
  155. },
  156. {
  157. 'tunnel': tunnel.pk,
  158. 'role': TunnelTerminationRoleChoices.ROLE_PEER,
  159. 'termination_type': 'dcim.interface',
  160. 'termination_id': interfaces[4].pk,
  161. },
  162. {
  163. 'tunnel': tunnel.pk,
  164. 'role': TunnelTerminationRoleChoices.ROLE_PEER,
  165. 'termination_type': 'dcim.interface',
  166. 'termination_id': interfaces[5].pk,
  167. },
  168. ]
  169. class IKEProposalTestCase(APIViewTestCases.APIViewTestCase):
  170. model = IKEProposal
  171. brief_fields = ['description', 'display', 'id', 'name', 'url']
  172. bulk_update_data = {
  173. 'authentication_method': AuthenticationMethodChoices.CERTIFICATES,
  174. 'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES192_CBC,
  175. 'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_MD5,
  176. 'group': DHGroupChoices.GROUP_19,
  177. 'description': 'New description',
  178. }
  179. bulk_update_invalid_data = {
  180. 'authentication_algorithm': 'not-a-valid-authentication-algorithm',
  181. }
  182. @classmethod
  183. def setUpTestData(cls):
  184. ike_proposals = (
  185. IKEProposal(
  186. name='IKE Proposal 1',
  187. authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
  188. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  189. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
  190. group=DHGroupChoices.GROUP_14
  191. ),
  192. IKEProposal(
  193. name='IKE Proposal 2',
  194. authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
  195. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  196. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
  197. group=DHGroupChoices.GROUP_14
  198. ),
  199. IKEProposal(
  200. name='IKE Proposal 3',
  201. authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
  202. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  203. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
  204. group=DHGroupChoices.GROUP_14
  205. ),
  206. )
  207. IKEProposal.objects.bulk_create(ike_proposals)
  208. cls.create_data = [
  209. {
  210. 'name': 'IKE Proposal 4',
  211. 'authentication_method': AuthenticationMethodChoices.CERTIFICATES,
  212. 'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES256_CBC,
  213. 'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
  214. 'group': DHGroupChoices.GROUP_19,
  215. },
  216. {
  217. 'name': 'IKE Proposal 5',
  218. 'authentication_method': AuthenticationMethodChoices.CERTIFICATES,
  219. 'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES256_CBC,
  220. 'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
  221. 'group': DHGroupChoices.GROUP_19,
  222. },
  223. {
  224. 'name': 'IKE Proposal 6',
  225. 'authentication_method': AuthenticationMethodChoices.CERTIFICATES,
  226. 'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES256_CBC,
  227. 'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
  228. 'group': DHGroupChoices.GROUP_19,
  229. },
  230. ]
  231. class IKEPolicyTestCase(APIViewTestCases.APIViewTestCase):
  232. model = IKEPolicy
  233. brief_fields = ['description', 'display', 'id', 'name', 'url']
  234. bulk_update_data = {
  235. 'version': IKEVersionChoices.VERSION_1,
  236. 'mode': IKEModeChoices.AGGRESSIVE,
  237. 'description': 'New description',
  238. 'preshared_key': 'New key',
  239. }
  240. bulk_update_invalid_data = {
  241. 'version': 'not-a-valid-version',
  242. }
  243. @classmethod
  244. def setUpTestData(cls):
  245. ike_proposals = (
  246. IKEProposal(
  247. name='IKE Proposal 1',
  248. authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
  249. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  250. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
  251. group=DHGroupChoices.GROUP_14
  252. ),
  253. IKEProposal(
  254. name='IKE Proposal 2',
  255. authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
  256. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  257. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
  258. group=DHGroupChoices.GROUP_14
  259. ),
  260. )
  261. IKEProposal.objects.bulk_create(ike_proposals)
  262. ike_policies = (
  263. IKEPolicy(
  264. name='IKE Policy 1',
  265. version=IKEVersionChoices.VERSION_1,
  266. mode=IKEModeChoices.MAIN,
  267. ),
  268. IKEPolicy(
  269. name='IKE Policy 2',
  270. version=IKEVersionChoices.VERSION_1,
  271. mode=IKEModeChoices.MAIN,
  272. ),
  273. IKEPolicy(
  274. name='IKE Policy 3',
  275. version=IKEVersionChoices.VERSION_1,
  276. mode=IKEModeChoices.MAIN,
  277. ),
  278. )
  279. IKEPolicy.objects.bulk_create(ike_policies)
  280. for ike_policy in ike_policies:
  281. ike_policy.proposals.set(ike_proposals)
  282. cls.create_data = [
  283. {
  284. 'name': 'IKE Policy 4',
  285. 'version': IKEVersionChoices.VERSION_1,
  286. 'mode': IKEModeChoices.MAIN,
  287. 'proposals': [ike_proposals[0].pk, ike_proposals[1].pk],
  288. },
  289. {
  290. 'name': 'IKE Policy 5',
  291. 'version': IKEVersionChoices.VERSION_1,
  292. 'mode': IKEModeChoices.MAIN,
  293. 'proposals': [ike_proposals[0].pk, ike_proposals[1].pk],
  294. },
  295. {
  296. 'name': 'IKE Policy 6',
  297. 'version': IKEVersionChoices.VERSION_1,
  298. 'mode': IKEModeChoices.MAIN,
  299. 'proposals': [ike_proposals[0].pk, ike_proposals[1].pk],
  300. },
  301. ]
  302. class IPSecProposalTestCase(APIViewTestCases.APIViewTestCase):
  303. model = IPSecProposal
  304. brief_fields = ['description', 'display', 'id', 'name', 'url']
  305. bulk_update_data = {
  306. 'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES192_CBC,
  307. 'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_MD5,
  308. 'description': 'New description',
  309. }
  310. bulk_update_invalid_data = {
  311. 'encryption_algorithm': 'not-a-valid-encryption-algorithm',
  312. }
  313. @classmethod
  314. def setUpTestData(cls):
  315. ipsec_proposals = (
  316. IPSecProposal(
  317. name='IPSec Proposal 1',
  318. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  319. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1
  320. ),
  321. IPSecProposal(
  322. name='IPSec Proposal 2',
  323. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  324. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1
  325. ),
  326. IPSecProposal(
  327. name='IPSec Proposal 3',
  328. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  329. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1
  330. ),
  331. )
  332. IPSecProposal.objects.bulk_create(ipsec_proposals)
  333. cls.create_data = [
  334. {
  335. 'name': 'IPSec Proposal 4',
  336. 'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES256_CBC,
  337. 'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
  338. },
  339. {
  340. 'name': 'IPSec Proposal 5',
  341. 'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES256_CBC,
  342. 'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
  343. },
  344. {
  345. 'name': 'IPSec Proposal 6',
  346. 'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES256_CBC,
  347. 'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
  348. },
  349. ]
  350. class IPSecPolicyTestCase(APIViewTestCases.APIViewTestCase):
  351. model = IPSecPolicy
  352. brief_fields = ['description', 'display', 'id', 'name', 'url']
  353. bulk_update_data = {
  354. 'pfs_group': DHGroupChoices.GROUP_5,
  355. 'description': 'New description',
  356. }
  357. bulk_update_invalid_data = {
  358. 'pfs_group': 'not-a-valid-pfs-group',
  359. }
  360. @classmethod
  361. def setUpTestData(cls):
  362. ipsec_proposals = (
  363. IPSecProposal(
  364. name='IPSec Policy 1',
  365. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  366. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1
  367. ),
  368. IPSecProposal(
  369. name='IPSec Proposal 2',
  370. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  371. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1
  372. ),
  373. )
  374. IPSecProposal.objects.bulk_create(ipsec_proposals)
  375. ipsec_policies = (
  376. IPSecPolicy(
  377. name='IPSec Policy 1',
  378. pfs_group=DHGroupChoices.GROUP_14
  379. ),
  380. IPSecPolicy(
  381. name='IPSec Policy 2',
  382. pfs_group=DHGroupChoices.GROUP_14
  383. ),
  384. IPSecPolicy(
  385. name='IPSec Policy 3',
  386. pfs_group=DHGroupChoices.GROUP_14
  387. ),
  388. )
  389. IPSecPolicy.objects.bulk_create(ipsec_policies)
  390. for ipsec_policy in ipsec_policies:
  391. ipsec_policy.proposals.set(ipsec_proposals)
  392. cls.create_data = [
  393. {
  394. 'name': 'IPSec Policy 4',
  395. 'pfs_group': DHGroupChoices.GROUP_16,
  396. 'proposals': [ipsec_proposals[0].pk, ipsec_proposals[1].pk],
  397. },
  398. {
  399. 'name': 'IPSec Policy 5',
  400. 'pfs_group': DHGroupChoices.GROUP_16,
  401. 'proposals': [ipsec_proposals[0].pk, ipsec_proposals[1].pk],
  402. },
  403. {
  404. 'name': 'IPSec Policy 6',
  405. 'pfs_group': DHGroupChoices.GROUP_16,
  406. 'proposals': [ipsec_proposals[0].pk, ipsec_proposals[1].pk],
  407. },
  408. ]
  409. class IPSecProfileTestCase(APIViewTestCases.APIViewTestCase):
  410. model = IPSecProfile
  411. brief_fields = ['description', 'display', 'id', 'name', 'url']
  412. user_permissions = ('vpn.view_ikepolicy', 'vpn.view_ipsecpolicy')
  413. @classmethod
  414. def setUpTestData(cls):
  415. ike_proposal = IKEProposal.objects.create(
  416. name='IKE Proposal 1',
  417. authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
  418. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  419. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
  420. group=DHGroupChoices.GROUP_14
  421. )
  422. ipsec_proposal = IPSecProposal.objects.create(
  423. name='IPSec Proposal 1',
  424. encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
  425. authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1
  426. )
  427. ike_policies = (
  428. IKEPolicy(
  429. name='IKE Policy 1',
  430. version=IKEVersionChoices.VERSION_1,
  431. mode=IKEModeChoices.MAIN,
  432. ),
  433. IKEPolicy(
  434. name='IKE Policy 2',
  435. version=IKEVersionChoices.VERSION_1,
  436. mode=IKEModeChoices.MAIN,
  437. ),
  438. )
  439. IKEPolicy.objects.bulk_create(ike_policies)
  440. for ike_policy in ike_policies:
  441. ike_policy.proposals.add(ike_proposal)
  442. ipsec_policies = (
  443. IPSecPolicy(
  444. name='IPSec Policy 1',
  445. pfs_group=DHGroupChoices.GROUP_14
  446. ),
  447. IPSecPolicy(
  448. name='IPSec Policy 2',
  449. pfs_group=DHGroupChoices.GROUP_14
  450. ),
  451. )
  452. IPSecPolicy.objects.bulk_create(ipsec_policies)
  453. for ipsec_policy in ipsec_policies:
  454. ipsec_policy.proposals.add(ipsec_proposal)
  455. ipsec_profiles = (
  456. IPSecProfile(
  457. name='IPSec Profile 1',
  458. mode=IPSecModeChoices.ESP,
  459. ike_policy=ike_policies[0],
  460. ipsec_policy=ipsec_policies[0]
  461. ),
  462. IPSecProfile(
  463. name='IPSec Profile 2',
  464. mode=IPSecModeChoices.ESP,
  465. ike_policy=ike_policies[0],
  466. ipsec_policy=ipsec_policies[0]
  467. ),
  468. IPSecProfile(
  469. name='IPSec Profile 3',
  470. mode=IPSecModeChoices.ESP,
  471. ike_policy=ike_policies[0],
  472. ipsec_policy=ipsec_policies[0]
  473. ),
  474. )
  475. IPSecProfile.objects.bulk_create(ipsec_profiles)
  476. cls.create_data = [
  477. {
  478. 'name': 'IPSec Profile 4',
  479. 'mode': IPSecModeChoices.AH,
  480. 'ike_policy': ike_policies[1].pk,
  481. 'ipsec_policy': ipsec_policies[1].pk,
  482. },
  483. ]
  484. cls.bulk_update_data = {
  485. 'mode': IPSecModeChoices.AH,
  486. 'ike_policy': ike_policies[1].pk,
  487. 'ipsec_policy': ipsec_policies[1].pk,
  488. 'description': 'New description',
  489. }
  490. cls.bulk_update_invalid_data = {
  491. 'mode': 'not-a-valid-mode',
  492. }
  493. class L2VPNTestCase(APIViewTestCases.APIViewTestCase):
  494. model = L2VPN
  495. brief_fields = ['description', 'display', 'id', 'identifier', 'name', 'slug', 'type', 'url']
  496. create_data = [
  497. {
  498. 'name': 'L2VPN 4',
  499. 'slug': 'l2vpn-4',
  500. 'type': 'vxlan',
  501. 'identifier': 33343344,
  502. 'status': L2VPNStatusChoices.STATUS_ACTIVE,
  503. },
  504. {
  505. 'name': 'L2VPN 5',
  506. 'slug': 'l2vpn-5',
  507. 'type': 'vxlan',
  508. 'identifier': 33343345,
  509. 'status': L2VPNStatusChoices.STATUS_PLANNED,
  510. },
  511. {
  512. 'name': 'L2VPN 6',
  513. 'slug': 'l2vpn-6',
  514. 'type': 'vpws',
  515. 'identifier': 33343346,
  516. 'status': L2VPNStatusChoices.STATUS_DECOMMISSIONING,
  517. },
  518. ]
  519. bulk_update_data = {
  520. 'description': 'New description',
  521. }
  522. bulk_update_invalid_data = {
  523. 'status': 'not-a-valid-status',
  524. }
  525. @classmethod
  526. def setUpTestData(cls):
  527. l2vpns = (
  528. L2VPN(
  529. name='L2VPN 1', slug='l2vpn-1', type='vxlan', identifier=650001,
  530. status=L2VPNStatusChoices.STATUS_ACTIVE,
  531. ),
  532. L2VPN(
  533. name='L2VPN 2', slug='l2vpn-2', type='vpws', identifier=650002,
  534. status=L2VPNStatusChoices.STATUS_PLANNED,
  535. ),
  536. L2VPN(
  537. name='L2VPN 3', slug='l2vpn-3', type='vpls',
  538. status=L2VPNStatusChoices.STATUS_DECOMMISSIONING,
  539. ), # No RD
  540. )
  541. L2VPN.objects.bulk_create(l2vpns)
  542. def test_status_filter(self):
  543. url = reverse('vpn-api:l2vpn-list')
  544. self.add_permissions('vpn.view_l2vpn')
  545. response = self.client.get(url, **self.header)
  546. response_data = response.json()
  547. # all L2VPNs present with not filter
  548. self.assertHttpStatus(response, status.HTTP_200_OK)
  549. self.assertEqual(response_data['count'], 3)
  550. # 1 L2VPN present with active status filter
  551. filter_url = f'{url}?status={L2VPNStatusChoices.STATUS_ACTIVE}'
  552. response = self.client.get(filter_url, **self.header)
  553. response_data = response.json()
  554. self.assertHttpStatus(response, status.HTTP_200_OK)
  555. self.assertEqual(response_data['count'], 1)
  556. # 2 L2VPNs present with active and planned status filter
  557. filter_url = f'{filter_url}&status={L2VPNStatusChoices.STATUS_PLANNED}'
  558. response = self.client.get(filter_url, **self.header)
  559. response_data = response.json()
  560. self.assertHttpStatus(response, status.HTTP_200_OK)
  561. self.assertEqual(response_data['count'], 2)
  562. # 1 L2VPN present with decommissioning status filter
  563. filter_url = f'{url}?status={L2VPNStatusChoices.STATUS_DECOMMISSIONING}'
  564. response = self.client.get(filter_url, **self.header)
  565. response_data = response.json()
  566. self.assertHttpStatus(response, status.HTTP_200_OK)
  567. self.assertEqual(response_data['count'], 1)
  568. def test_type_required(self):
  569. """
  570. type must be reported as required by OPTIONS, and a POST omitting it must
  571. be rejected with a normal "required" validation error rather than a
  572. model-level "cannot be blank" error.
  573. """
  574. self.add_permissions('vpn.add_l2vpn')
  575. response = self.client.options(self._get_list_url(), **self.header)
  576. self.assertHttpStatus(response, status.HTTP_200_OK)
  577. self.assertTrue(response.data['actions']['POST']['type']['required'])
  578. data = {
  579. 'name': 'L2VPN Missing Type',
  580. 'slug': 'l2vpn-missing-type',
  581. }
  582. response = self.client.post(self._get_list_url(), data, format='json', **self.header)
  583. self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
  584. self.assertEqual(response.data['type'][0].code, 'required')
  585. class L2VPNTerminationTestCase(APIViewTestCases.APIViewTestCase):
  586. model = L2VPNTermination
  587. brief_fields = ['display', 'id', 'l2vpn', 'url']
  588. user_permissions = ('dcim.view_location', 'vpn.view_l2vpn')
  589. @classmethod
  590. def setUpTestData(cls):
  591. vlans = (
  592. VLAN(name='VLAN 1', vid=651),
  593. VLAN(name='VLAN 2', vid=652),
  594. VLAN(name='VLAN 3', vid=653),
  595. VLAN(name='VLAN 4', vid=654),
  596. VLAN(name='VLAN 5', vid=655),
  597. VLAN(name='VLAN 6', vid=656),
  598. VLAN(name='VLAN 7', vid=657)
  599. )
  600. VLAN.objects.bulk_create(vlans)
  601. l2vpns = (
  602. L2VPN(name='L2VPN 1', slug='l2vpn-1', type='vxlan', identifier=650001),
  603. L2VPN(name='L2VPN 2', slug='l2vpn-2', type='vpws', identifier=650002),
  604. L2VPN(name='L2VPN 3', slug='l2vpn-3', type='vpls'), # No RD
  605. )
  606. L2VPN.objects.bulk_create(l2vpns)
  607. ip_address = IPAddress.objects.create(address='192.0.2.1/32')
  608. l2vpnterminations = (
  609. L2VPNTermination(l2vpn=l2vpns[0], assigned_object=vlans[0]),
  610. L2VPNTermination(l2vpn=l2vpns[0], assigned_object=vlans[1]),
  611. L2VPNTermination(l2vpn=l2vpns[1], assigned_object=ip_address)
  612. )
  613. L2VPNTermination.objects.bulk_create(l2vpnterminations)
  614. cls.create_data = [
  615. {
  616. 'l2vpn': l2vpns[0].pk,
  617. 'assigned_object_type': 'ipam.vlan',
  618. 'assigned_object_id': vlans[3].pk,
  619. },
  620. {
  621. 'l2vpn': l2vpns[0].pk,
  622. 'assigned_object_type': 'ipam.vlan',
  623. 'assigned_object_id': vlans[4].pk,
  624. },
  625. {
  626. # The same IP address may terminate another L2VPN
  627. 'l2vpn': l2vpns[2].pk,
  628. 'assigned_object_type': 'ipam.ipaddress',
  629. 'assigned_object_id': ip_address.pk,
  630. },
  631. ]
  632. cls.bulk_update_data = {
  633. 'l2vpn': l2vpns[2].pk
  634. }
  635. cls.bulk_update_invalid_data = {
  636. 'l2vpn': 99999,
  637. }
  638. def test_graphql_ip_address_l2vpn_terminations_filter(self):
  639. """IP addresses can be filtered over GraphQL by the L2VPNs they terminate."""
  640. self.add_permissions('ipam.view_ipaddress')
  641. IPAddress.objects.create(address='192.0.2.2/32')
  642. l2vpn = L2VPN.objects.get(name='L2VPN 2')
  643. query = (
  644. f'{{ ip_address_list(filters: {{l2vpn_terminations: {{l2vpn_id: "{l2vpn.pk}"}}}}) {{ address }} }}'
  645. )
  646. response = self.client.post(reverse('graphql'), data={'query': query}, format='json', **self.header)
  647. self.assertHttpStatus(response, status.HTTP_200_OK)
  648. data = json.loads(response.content)
  649. self.assertNotIn('errors', data)
  650. self.assertEqual([ip['address'] for ip in data['data']['ip_address_list']], ['192.0.2.1/32'])