test_cablepaths.py 122 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341
  1. from io import StringIO
  2. from django.core.management import call_command
  3. from circuits.models import *
  4. from dcim.choices import CableEndChoices, LinkStatusChoices
  5. from dcim.models import *
  6. from dcim.svg import CableTraceSVG
  7. from dcim.tests.utils import BaseCablePathTestCase
  8. from dcim.utils import create_cablepaths, object_to_path_node
  9. from utilities.exceptions import AbortRequest
  10. class LegacyCablePathTestCase(BaseCablePathTestCase):
  11. """
  12. Test NetBox's ability to trace and retrace CablePaths in response to data model changes, without cable profiles.
  13. Tests are numbered as follows:
  14. 1XX: Test direct connections between different endpoint types
  15. 2XX: Test different cable topologies
  16. 3XX: Test responses to changes in existing objects
  17. 4XX: Test to exclude specific cable topologies
  18. """
  19. def test_101_interface_to_interface(self):
  20. """
  21. [IF1] --C1-- [IF2]
  22. """
  23. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  24. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  25. # Create cable 1
  26. cable1 = Cable(
  27. a_terminations=[interface1],
  28. b_terminations=[interface2]
  29. )
  30. cable1.save()
  31. path1 = self.assertPathExists(
  32. (interface1, cable1, interface2),
  33. is_complete=True,
  34. is_active=True
  35. )
  36. path2 = self.assertPathExists(
  37. (interface2, cable1, interface1),
  38. is_complete=True,
  39. is_active=True
  40. )
  41. self.assertEqual(CablePath.objects.count(), 2)
  42. interface1.refresh_from_db()
  43. interface2.refresh_from_db()
  44. self.assertPathIsSet(interface1, path1)
  45. self.assertPathIsSet(interface2, path2)
  46. # Test SVG generation
  47. CableTraceSVG(interface1).render()
  48. # Delete cable 1
  49. cable1.delete()
  50. # Check that all CablePaths have been deleted
  51. self.assertEqual(CablePath.objects.count(), 0)
  52. # Check that connected interfaces are fully cleaned up
  53. interface1.refresh_from_db()
  54. interface2.refresh_from_db()
  55. self.assertIsNone(interface1.cable_id)
  56. self.assertIsNone(interface1.cable_end)
  57. self.assertPathIsNotSet(interface1)
  58. self.assertIsNone(interface2.cable_id)
  59. self.assertIsNone(interface2.cable_end)
  60. self.assertPathIsNotSet(interface2)
  61. def test_102_consoleport_to_consoleserverport(self):
  62. """
  63. [CP1] --C1-- [CSP1]
  64. """
  65. consoleport1 = ConsolePort.objects.create(device=self.device, name='Console Port 1')
  66. consoleserverport1 = ConsoleServerPort.objects.create(device=self.device, name='Console Server Port 1')
  67. # Create cable 1
  68. cable1 = Cable(
  69. a_terminations=[consoleport1],
  70. b_terminations=[consoleserverport1]
  71. )
  72. cable1.save()
  73. path1 = self.assertPathExists(
  74. (consoleport1, cable1, consoleserverport1),
  75. is_complete=True,
  76. is_active=True
  77. )
  78. path2 = self.assertPathExists(
  79. (consoleserverport1, cable1, consoleport1),
  80. is_complete=True,
  81. is_active=True
  82. )
  83. self.assertEqual(CablePath.objects.count(), 2)
  84. consoleport1.refresh_from_db()
  85. consoleserverport1.refresh_from_db()
  86. self.assertPathIsSet(consoleport1, path1)
  87. self.assertPathIsSet(consoleserverport1, path2)
  88. # Test SVG generation
  89. CableTraceSVG(consoleport1).render()
  90. # Delete cable 1
  91. cable1.delete()
  92. # Check that all CablePaths have been deleted
  93. self.assertEqual(CablePath.objects.count(), 0)
  94. def test_103_powerport_to_poweroutlet(self):
  95. """
  96. [PP1] --C1-- [PO1]
  97. """
  98. powerport1 = PowerPort.objects.create(device=self.device, name='Power Port 1')
  99. poweroutlet1 = PowerOutlet.objects.create(device=self.device, name='Power Outlet 1')
  100. # Create cable 1
  101. cable1 = Cable(
  102. a_terminations=[powerport1],
  103. b_terminations=[poweroutlet1]
  104. )
  105. cable1.save()
  106. path1 = self.assertPathExists(
  107. (powerport1, cable1, poweroutlet1),
  108. is_complete=True,
  109. is_active=True
  110. )
  111. path2 = self.assertPathExists(
  112. (poweroutlet1, cable1, powerport1),
  113. is_complete=True,
  114. is_active=True
  115. )
  116. self.assertEqual(CablePath.objects.count(), 2)
  117. powerport1.refresh_from_db()
  118. poweroutlet1.refresh_from_db()
  119. self.assertPathIsSet(powerport1, path1)
  120. self.assertPathIsSet(poweroutlet1, path2)
  121. # Test SVG generation
  122. CableTraceSVG(powerport1).render()
  123. # Delete cable 1
  124. cable1.delete()
  125. # Check that all CablePaths have been deleted
  126. self.assertEqual(CablePath.objects.count(), 0)
  127. def test_104_powerport_to_powerfeed(self):
  128. """
  129. [PP1] --C1-- [PF1]
  130. """
  131. powerport1 = PowerPort.objects.create(device=self.device, name='Power Port 1')
  132. powerfeed1 = PowerFeed.objects.create(power_panel=self.powerpanel, name='Power Feed 1')
  133. # Create cable 1
  134. cable1 = Cable(
  135. a_terminations=[powerport1],
  136. b_terminations=[powerfeed1]
  137. )
  138. cable1.save()
  139. path1 = self.assertPathExists(
  140. (powerport1, cable1, powerfeed1),
  141. is_complete=True,
  142. is_active=True
  143. )
  144. path2 = self.assertPathExists(
  145. (powerfeed1, cable1, powerport1),
  146. is_complete=True,
  147. is_active=True
  148. )
  149. self.assertEqual(CablePath.objects.count(), 2)
  150. powerport1.refresh_from_db()
  151. powerfeed1.refresh_from_db()
  152. self.assertPathIsSet(powerport1, path1)
  153. self.assertPathIsSet(powerfeed1, path2)
  154. # Test SVG generation
  155. CableTraceSVG(powerport1).render()
  156. # Delete cable 1
  157. cable1.delete()
  158. # Check that all CablePaths have been deleted
  159. self.assertEqual(CablePath.objects.count(), 0)
  160. def test_120_single_interface_to_multi_interface(self):
  161. """
  162. [IF1] --C1-- [IF2]
  163. [IF3]
  164. """
  165. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  166. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  167. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  168. # Create cable 1
  169. cable1 = Cable(
  170. a_terminations=[interface1],
  171. b_terminations=[interface2, interface3]
  172. )
  173. cable1.save()
  174. path1 = self.assertPathExists(
  175. (interface1, cable1, (interface2, interface3)),
  176. is_complete=True,
  177. is_active=True
  178. )
  179. path2 = self.assertPathExists(
  180. ((interface2, interface3), cable1, interface1),
  181. is_complete=True,
  182. is_active=True
  183. )
  184. self.assertEqual(CablePath.objects.count(), 2)
  185. interface1.refresh_from_db()
  186. interface2.refresh_from_db()
  187. interface3.refresh_from_db()
  188. self.assertPathIsSet(interface1, path1)
  189. self.assertPathIsSet(interface2, path2)
  190. self.assertPathIsSet(interface3, path2)
  191. # Test SVG generation
  192. CableTraceSVG(interface1).render()
  193. # Delete cable 1
  194. cable1.delete()
  195. # Check that all CablePaths have been deleted
  196. self.assertEqual(CablePath.objects.count(), 0)
  197. interface1.refresh_from_db()
  198. interface2.refresh_from_db()
  199. interface3.refresh_from_db()
  200. self.assertPathIsNotSet(interface1)
  201. self.assertPathIsNotSet(interface2)
  202. self.assertPathIsNotSet(interface3)
  203. def test_121_multi_interface_to_multi_interface(self):
  204. """
  205. [IF1] --C1-- [IF3]
  206. [IF2] [IF4]
  207. """
  208. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  209. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  210. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  211. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  212. # Create cable 1
  213. cable1 = Cable(
  214. a_terminations=[interface1, interface2],
  215. b_terminations=[interface3, interface4]
  216. )
  217. cable1.save()
  218. path1 = self.assertPathExists(
  219. ((interface1, interface2), cable1, (interface3, interface4)),
  220. is_complete=True,
  221. is_active=True
  222. )
  223. path2 = self.assertPathExists(
  224. ((interface3, interface4), cable1, (interface1, interface2)),
  225. is_complete=True,
  226. is_active=True
  227. )
  228. self.assertEqual(CablePath.objects.count(), 2)
  229. interface1.refresh_from_db()
  230. interface2.refresh_from_db()
  231. interface3.refresh_from_db()
  232. interface4.refresh_from_db()
  233. self.assertPathIsSet(interface1, path1)
  234. self.assertPathIsSet(interface2, path1)
  235. self.assertPathIsSet(interface3, path2)
  236. self.assertPathIsSet(interface4, path2)
  237. # Test SVG generation
  238. CableTraceSVG(interface1).render()
  239. # Delete cable 1
  240. cable1.delete()
  241. # Check that all CablePaths have been deleted
  242. self.assertEqual(CablePath.objects.count(), 0)
  243. interface1.refresh_from_db()
  244. interface2.refresh_from_db()
  245. interface3.refresh_from_db()
  246. interface4.refresh_from_db()
  247. self.assertPathIsNotSet(interface1)
  248. self.assertPathIsNotSet(interface2)
  249. self.assertPathIsNotSet(interface3)
  250. self.assertPathIsNotSet(interface4)
  251. def test_201_single_path_via_pass_through(self):
  252. """
  253. [IF1] --C1-- [FP1] [RP1] --C2-- [IF2]
  254. """
  255. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  256. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  257. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  258. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  259. PortMapping.objects.create(
  260. device=self.device,
  261. front_port=frontport1,
  262. front_port_position=1,
  263. rear_port=rearport1,
  264. rear_port_position=1
  265. )
  266. # Create cable 1
  267. cable1 = Cable(
  268. a_terminations=[interface1],
  269. b_terminations=[frontport1]
  270. )
  271. cable1.save()
  272. self.assertPathExists(
  273. (interface1, cable1, frontport1, rearport1),
  274. is_complete=False
  275. )
  276. self.assertEqual(CablePath.objects.count(), 1)
  277. # Create cable 2
  278. cable2 = Cable(
  279. a_terminations=[rearport1],
  280. b_terminations=[interface2]
  281. )
  282. cable2.save()
  283. self.assertPathExists(
  284. (interface1, cable1, frontport1, rearport1, cable2, interface2),
  285. is_complete=True,
  286. is_active=True
  287. )
  288. self.assertPathExists(
  289. (interface2, cable2, rearport1, frontport1, cable1, interface1),
  290. is_complete=True,
  291. is_active=True
  292. )
  293. self.assertEqual(CablePath.objects.count(), 2)
  294. # Test SVG generation
  295. CableTraceSVG(interface1).render()
  296. # Delete cable 2
  297. cable2.delete()
  298. path1 = self.assertPathExists(
  299. (interface1, cable1, frontport1, rearport1),
  300. is_complete=False
  301. )
  302. self.assertEqual(CablePath.objects.count(), 1)
  303. interface1.refresh_from_db()
  304. interface2.refresh_from_db()
  305. self.assertPathIsSet(interface1, path1)
  306. self.assertPathIsNotSet(interface2)
  307. def test_202_single_path_via_pass_through_with_breakouts(self):
  308. """
  309. [IF1] --C1-- [FP1] [RP1] --C2-- [IF3]
  310. [IF2] [IF4]
  311. """
  312. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  313. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  314. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  315. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  316. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  317. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  318. PortMapping.objects.create(
  319. device=self.device,
  320. front_port=frontport1,
  321. front_port_position=1,
  322. rear_port=rearport1,
  323. rear_port_position=1
  324. )
  325. # Create cable 1
  326. cable1 = Cable(
  327. a_terminations=[interface1, interface2],
  328. b_terminations=[frontport1]
  329. )
  330. cable1.save()
  331. self.assertPathExists(
  332. ([interface1, interface2], cable1, frontport1, rearport1),
  333. is_complete=False
  334. )
  335. self.assertEqual(CablePath.objects.count(), 1)
  336. # Create cable 2
  337. cable2 = Cable(
  338. a_terminations=[rearport1],
  339. b_terminations=[interface3, interface4]
  340. )
  341. cable2.save()
  342. self.assertPathExists(
  343. ([interface1, interface2], cable1, frontport1, rearport1, cable2, [interface3, interface4]),
  344. is_complete=True,
  345. is_active=True
  346. )
  347. self.assertPathExists(
  348. ([interface3, interface4], cable2, rearport1, frontport1, cable1, [interface1, interface2]),
  349. is_complete=True,
  350. is_active=True
  351. )
  352. self.assertEqual(CablePath.objects.count(), 2)
  353. # Test SVG generation
  354. CableTraceSVG(interface1).render()
  355. # Delete cable 2
  356. cable2.delete()
  357. path1 = self.assertPathExists(
  358. ([interface1, interface2], cable1, frontport1, rearport1),
  359. is_complete=False
  360. )
  361. self.assertEqual(CablePath.objects.count(), 1)
  362. interface1.refresh_from_db()
  363. interface2.refresh_from_db()
  364. self.assertPathIsSet(interface1, path1)
  365. self.assertPathIsSet(interface2, path1)
  366. self.assertPathIsNotSet(interface3)
  367. self.assertPathIsNotSet(interface4)
  368. def test_203_multiple_paths_via_pass_through(self):
  369. """
  370. [IF1] --C1-- [FP1:1] [RP1] --C3-- [RP2] [FP2:1] --C4-- [IF3]
  371. [IF2] --C2-- [FP1:2] [FP2:2] --C5-- [IF4]
  372. """
  373. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  374. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  375. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  376. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  377. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1', positions=4)
  378. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2', positions=4)
  379. frontport1_1 = FrontPort.objects.create(device=self.device, name='Front Port 1:1')
  380. frontport1_2 = FrontPort.objects.create(device=self.device, name='Front Port 1:2')
  381. frontport2_1 = FrontPort.objects.create(device=self.device, name='Front Port 2:1')
  382. frontport2_2 = FrontPort.objects.create(device=self.device, name='Front Port 2:2')
  383. PortMapping.objects.bulk_create([
  384. PortMapping(
  385. device=self.device,
  386. front_port=frontport1_1,
  387. front_port_position=1,
  388. rear_port=rearport1,
  389. rear_port_position=1,
  390. ),
  391. PortMapping(
  392. device=self.device,
  393. front_port=frontport1_2,
  394. front_port_position=1,
  395. rear_port=rearport1,
  396. rear_port_position=2,
  397. ),
  398. PortMapping(
  399. device=self.device,
  400. front_port=frontport2_1,
  401. front_port_position=1,
  402. rear_port=rearport2,
  403. rear_port_position=1,
  404. ),
  405. PortMapping(
  406. device=self.device,
  407. front_port=frontport2_2,
  408. front_port_position=1,
  409. rear_port=rearport2,
  410. rear_port_position=2,
  411. ),
  412. ])
  413. # Create cables 1-2
  414. cable1 = Cable(
  415. a_terminations=[interface1],
  416. b_terminations=[frontport1_1]
  417. )
  418. cable1.save()
  419. cable2 = Cable(
  420. a_terminations=[interface2],
  421. b_terminations=[frontport1_2]
  422. )
  423. cable2.save()
  424. self.assertPathExists(
  425. (interface1, cable1, frontport1_1, rearport1),
  426. is_complete=False
  427. )
  428. self.assertPathExists(
  429. (interface2, cable2, frontport1_2, rearport1),
  430. is_complete=False
  431. )
  432. self.assertEqual(CablePath.objects.count(), 2)
  433. # Create cable 3
  434. cable3 = Cable(
  435. a_terminations=[rearport1],
  436. b_terminations=[rearport2]
  437. )
  438. cable3.save()
  439. self.assertPathExists(
  440. (interface1, cable1, frontport1_1, rearport1, cable3, rearport2, frontport2_1),
  441. is_complete=False
  442. )
  443. self.assertPathExists(
  444. (interface2, cable2, frontport1_2, rearport1, cable3, rearport2, frontport2_2),
  445. is_complete=False
  446. )
  447. self.assertEqual(CablePath.objects.count(), 2)
  448. # Create cables 4-5
  449. cable4 = Cable(
  450. a_terminations=[frontport2_1],
  451. b_terminations=[interface3]
  452. )
  453. cable4.save()
  454. cable5 = Cable(
  455. a_terminations=[frontport2_2],
  456. b_terminations=[interface4]
  457. )
  458. cable5.save()
  459. path1 = self.assertPathExists(
  460. (interface1, cable1, frontport1_1, rearport1, cable3, rearport2, frontport2_1, cable4, interface3),
  461. is_complete=True,
  462. is_active=True
  463. )
  464. path2 = self.assertPathExists(
  465. (interface2, cable2, frontport1_2, rearport1, cable3, rearport2, frontport2_2, cable5, interface4),
  466. is_complete=True,
  467. is_active=True
  468. )
  469. path3 = self.assertPathExists(
  470. (interface3, cable4, frontport2_1, rearport2, cable3, rearport1, frontport1_1, cable1, interface1),
  471. is_complete=True,
  472. is_active=True
  473. )
  474. path4 = self.assertPathExists(
  475. (interface4, cable5, frontport2_2, rearport2, cable3, rearport1, frontport1_2, cable2, interface2),
  476. is_complete=True,
  477. is_active=True
  478. )
  479. self.assertEqual(CablePath.objects.count(), 4)
  480. # Test SVG generation
  481. CableTraceSVG(interface1).render()
  482. # Delete cable 3
  483. cable3.delete()
  484. # Check for four partial paths; one from each interface
  485. self.assertEqual(CablePath.objects.filter(is_complete=False).count(), 4)
  486. self.assertEqual(CablePath.objects.filter(is_complete=True).count(), 0)
  487. interface1.refresh_from_db()
  488. interface2.refresh_from_db()
  489. interface3.refresh_from_db()
  490. interface4.refresh_from_db()
  491. self.assertPathIsSet(interface1, path1)
  492. self.assertPathIsSet(interface2, path2)
  493. self.assertPathIsSet(interface3, path3)
  494. self.assertPathIsSet(interface4, path4)
  495. def test_204_multiple_paths_via_pass_through_with_breakouts(self):
  496. """
  497. [IF1] --C1-- [FP1:1] [RP1] --C3-- [RP2] [FP2:1] --C4-- [IF4]
  498. [IF2] [IF5]
  499. [IF3] --C2-- [FP1:2] [FP2:2] --C5-- [IF6]
  500. [IF4] [IF7]
  501. """
  502. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  503. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  504. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  505. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  506. interface5 = Interface.objects.create(device=self.device, name='Interface 5')
  507. interface6 = Interface.objects.create(device=self.device, name='Interface 6')
  508. interface7 = Interface.objects.create(device=self.device, name='Interface 7')
  509. interface8 = Interface.objects.create(device=self.device, name='Interface 8')
  510. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1', positions=4)
  511. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2', positions=4)
  512. frontport1_1 = FrontPort.objects.create(device=self.device, name='Front Port 1:1')
  513. frontport1_2 = FrontPort.objects.create(device=self.device, name='Front Port 1:2')
  514. frontport2_1 = FrontPort.objects.create(device=self.device, name='Front Port 2:1')
  515. frontport2_2 = FrontPort.objects.create(device=self.device, name='Front Port 2:2')
  516. PortMapping.objects.bulk_create([
  517. PortMapping(
  518. device=self.device,
  519. front_port=frontport1_1,
  520. front_port_position=1,
  521. rear_port=rearport1,
  522. rear_port_position=1,
  523. ),
  524. PortMapping(
  525. device=self.device,
  526. front_port=frontport1_2,
  527. front_port_position=1,
  528. rear_port=rearport1,
  529. rear_port_position=2,
  530. ),
  531. PortMapping(
  532. device=self.device,
  533. front_port=frontport2_1,
  534. front_port_position=1,
  535. rear_port=rearport2,
  536. rear_port_position=1,
  537. ),
  538. PortMapping(
  539. device=self.device,
  540. front_port=frontport2_2,
  541. front_port_position=1,
  542. rear_port=rearport2,
  543. rear_port_position=2,
  544. ),
  545. ])
  546. # Create cables 1-2
  547. cable1 = Cable(
  548. a_terminations=[interface1, interface2],
  549. b_terminations=[frontport1_1]
  550. )
  551. cable1.save()
  552. cable2 = Cable(
  553. a_terminations=[interface3, interface4],
  554. b_terminations=[frontport1_2]
  555. )
  556. cable2.save()
  557. self.assertPathExists(
  558. ([interface1, interface2], cable1, frontport1_1, rearport1),
  559. is_complete=False
  560. )
  561. self.assertPathExists(
  562. ([interface3, interface4], cable2, frontport1_2, rearport1),
  563. is_complete=False
  564. )
  565. self.assertEqual(CablePath.objects.count(), 2)
  566. # Create cable 3
  567. cable3 = Cable(
  568. a_terminations=[rearport1],
  569. b_terminations=[rearport2]
  570. )
  571. cable3.save()
  572. self.assertPathExists(
  573. ([interface1, interface2], cable1, frontport1_1, rearport1, cable3, rearport2, frontport2_1),
  574. is_complete=False
  575. )
  576. self.assertPathExists(
  577. ([interface3, interface4], cable2, frontport1_2, rearport1, cable3, rearport2, frontport2_2),
  578. is_complete=False
  579. )
  580. self.assertEqual(CablePath.objects.count(), 2)
  581. # Create cables 4-5
  582. cable4 = Cable(
  583. a_terminations=[frontport2_1],
  584. b_terminations=[interface5, interface6]
  585. )
  586. cable4.save()
  587. cable5 = Cable(
  588. a_terminations=[frontport2_2],
  589. b_terminations=[interface7, interface8]
  590. )
  591. cable5.save()
  592. path1 = self.assertPathExists(
  593. (
  594. [interface1, interface2],
  595. cable1,
  596. frontport1_1,
  597. rearport1,
  598. cable3,
  599. rearport2,
  600. frontport2_1,
  601. cable4,
  602. [interface5, interface6],
  603. ),
  604. is_complete=True,
  605. is_active=True,
  606. )
  607. path2 = self.assertPathExists(
  608. (
  609. [interface3, interface4],
  610. cable2,
  611. frontport1_2,
  612. rearport1,
  613. cable3,
  614. rearport2,
  615. frontport2_2,
  616. cable5,
  617. [interface7, interface8],
  618. ),
  619. is_complete=True,
  620. is_active=True,
  621. )
  622. path3 = self.assertPathExists(
  623. (
  624. [interface5, interface6],
  625. cable4,
  626. frontport2_1,
  627. rearport2,
  628. cable3,
  629. rearport1,
  630. frontport1_1,
  631. cable1,
  632. [interface1, interface2],
  633. ),
  634. is_complete=True,
  635. is_active=True,
  636. )
  637. path4 = self.assertPathExists(
  638. (
  639. [interface7, interface8],
  640. cable5,
  641. frontport2_2,
  642. rearport2,
  643. cable3,
  644. rearport1,
  645. frontport1_2,
  646. cable2,
  647. [interface3, interface4],
  648. ),
  649. is_complete=True,
  650. is_active=True,
  651. )
  652. self.assertEqual(CablePath.objects.count(), 4)
  653. # Test SVG generation
  654. CableTraceSVG(interface1).render()
  655. # Delete cable 3
  656. cable3.delete()
  657. # Check for four partial paths; one from each interface
  658. self.assertEqual(CablePath.objects.filter(is_complete=False).count(), 4)
  659. self.assertEqual(CablePath.objects.filter(is_complete=True).count(), 0)
  660. interface1.refresh_from_db()
  661. interface2.refresh_from_db()
  662. interface3.refresh_from_db()
  663. interface4.refresh_from_db()
  664. interface5.refresh_from_db()
  665. interface6.refresh_from_db()
  666. interface7.refresh_from_db()
  667. interface8.refresh_from_db()
  668. self.assertPathIsSet(interface1, path1)
  669. self.assertPathIsSet(interface2, path1)
  670. self.assertPathIsSet(interface3, path2)
  671. self.assertPathIsSet(interface4, path2)
  672. self.assertPathIsSet(interface5, path3)
  673. self.assertPathIsSet(interface6, path3)
  674. self.assertPathIsSet(interface7, path4)
  675. self.assertPathIsSet(interface8, path4)
  676. def test_205_multiple_paths_via_nested_pass_throughs(self):
  677. """
  678. [IF1] --C1-- [FP1:1] [RP1] --C3-- [FP2] [RP2] --C4-- [RP3] [FP3] --C5-- [RP4] [FP4:1] --C6-- [IF3]
  679. [IF2] --C2-- [FP1:2] [FP4:2] --C7-- [IF4]
  680. """
  681. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  682. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  683. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  684. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  685. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1', positions=4)
  686. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  687. rearport3 = RearPort.objects.create(device=self.device, name='Rear Port 3')
  688. rearport4 = RearPort.objects.create(device=self.device, name='Rear Port 4', positions=4)
  689. frontport1_1 = FrontPort.objects.create(device=self.device, name='Front Port 1:1')
  690. frontport1_2 = FrontPort.objects.create(device=self.device, name='Front Port 1:2')
  691. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  692. frontport3 = FrontPort.objects.create(device=self.device, name='Front Port 3')
  693. frontport4_1 = FrontPort.objects.create(device=self.device, name='Front Port 4:1')
  694. frontport4_2 = FrontPort.objects.create(device=self.device, name='Front Port 4:2')
  695. PortMapping.objects.bulk_create([
  696. PortMapping(
  697. device=self.device,
  698. front_port=frontport1_1,
  699. front_port_position=1,
  700. rear_port=rearport1,
  701. rear_port_position=1,
  702. ),
  703. PortMapping(
  704. device=self.device,
  705. front_port=frontport1_2,
  706. front_port_position=1,
  707. rear_port=rearport1,
  708. rear_port_position=2,
  709. ),
  710. PortMapping(
  711. device=self.device,
  712. front_port=frontport2,
  713. front_port_position=1,
  714. rear_port=rearport2,
  715. rear_port_position=1,
  716. ),
  717. PortMapping(
  718. device=self.device,
  719. front_port=frontport3,
  720. front_port_position=1,
  721. rear_port=rearport3,
  722. rear_port_position=1,
  723. ),
  724. PortMapping(
  725. device=self.device,
  726. front_port=frontport4_1,
  727. front_port_position=1,
  728. rear_port=rearport4,
  729. rear_port_position=1,
  730. ),
  731. PortMapping(
  732. device=self.device,
  733. front_port=frontport4_2,
  734. front_port_position=1,
  735. rear_port=rearport4,
  736. rear_port_position=2,
  737. ),
  738. ])
  739. # Create cables 1-2, 6-7
  740. cable1 = Cable(
  741. a_terminations=[interface1],
  742. b_terminations=[frontport1_1]
  743. )
  744. cable1.save()
  745. cable2 = Cable(
  746. a_terminations=[interface2],
  747. b_terminations=[frontport1_2]
  748. )
  749. cable2.save()
  750. cable6 = Cable(
  751. a_terminations=[interface3],
  752. b_terminations=[frontport4_1]
  753. )
  754. cable6.save()
  755. cable7 = Cable(
  756. a_terminations=[interface4],
  757. b_terminations=[frontport4_2]
  758. )
  759. cable7.save()
  760. self.assertEqual(CablePath.objects.count(), 4) # Four partial paths; one from each interface
  761. # Create cables 3 and 5
  762. cable3 = Cable(
  763. a_terminations=[rearport1],
  764. b_terminations=[frontport2]
  765. )
  766. cable3.save()
  767. cable5 = Cable(
  768. a_terminations=[rearport4],
  769. b_terminations=[frontport3]
  770. )
  771. cable5.save()
  772. self.assertEqual(CablePath.objects.count(), 4) # Four (longer) partial paths; one from each interface
  773. # Create cable 4
  774. cable4 = Cable(
  775. a_terminations=[rearport2],
  776. b_terminations=[rearport3]
  777. )
  778. cable4.save()
  779. self.assertPathExists(
  780. (
  781. interface1, cable1, frontport1_1, rearport1, cable3, frontport2, rearport2, cable4, rearport3,
  782. frontport3, cable5, rearport4, frontport4_1, cable6, interface3,
  783. ),
  784. is_complete=True,
  785. is_active=True
  786. )
  787. self.assertPathExists(
  788. (
  789. interface2, cable2, frontport1_2, rearport1, cable3, frontport2, rearport2, cable4, rearport3,
  790. frontport3, cable5, rearport4, frontport4_2, cable7, interface4,
  791. ),
  792. is_complete=True,
  793. is_active=True
  794. )
  795. self.assertPathExists(
  796. (
  797. interface3, cable6, frontport4_1, rearport4, cable5, frontport3, rearport3, cable4, rearport2,
  798. frontport2, cable3, rearport1, frontport1_1, cable1, interface1,
  799. ),
  800. is_complete=True,
  801. is_active=True
  802. )
  803. self.assertPathExists(
  804. (
  805. interface4, cable7, frontport4_2, rearport4, cable5, frontport3, rearport3, cable4, rearport2,
  806. frontport2, cable3, rearport1, frontport1_2, cable2, interface2,
  807. ),
  808. is_complete=True,
  809. is_active=True
  810. )
  811. self.assertEqual(CablePath.objects.count(), 4)
  812. # Test SVG generation
  813. CableTraceSVG(interface1).render()
  814. # Delete cable 3
  815. cable3.delete()
  816. # Check for four partial paths; one from each interface
  817. self.assertEqual(CablePath.objects.filter(is_complete=False).count(), 4)
  818. self.assertEqual(CablePath.objects.filter(is_complete=True).count(), 0)
  819. def test_206_multiple_paths_via_multiple_pass_throughs(self):
  820. """
  821. [IF1] --C1-- [FP1:1] [RP1] --C3-- [RP2] [FP2:1] --C4-- [FP3:1] [RP3] --C6-- [RP4] [FP4:1] --C7-- [IF3]
  822. [IF2] --C2-- [FP1:2] [FP2:1] --C5-- [FP3:1] [FP4:2] --C8-- [IF4]
  823. """
  824. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  825. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  826. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  827. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  828. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1', positions=4)
  829. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2', positions=4)
  830. rearport3 = RearPort.objects.create(device=self.device, name='Rear Port 3', positions=4)
  831. rearport4 = RearPort.objects.create(device=self.device, name='Rear Port 4', positions=4)
  832. frontport1_1 = FrontPort.objects.create(device=self.device, name='Front Port 1:1')
  833. frontport1_2 = FrontPort.objects.create(device=self.device, name='Front Port 1:2')
  834. frontport2_1 = FrontPort.objects.create(device=self.device, name='Front Port 2:1')
  835. frontport2_2 = FrontPort.objects.create(device=self.device, name='Front Port 2:2')
  836. frontport3_1 = FrontPort.objects.create(device=self.device, name='Front Port 3:1')
  837. frontport3_2 = FrontPort.objects.create(device=self.device, name='Front Port 3:2')
  838. frontport4_1 = FrontPort.objects.create(device=self.device, name='Front Port 4:1')
  839. frontport4_2 = FrontPort.objects.create(device=self.device, name='Front Port 4:2')
  840. PortMapping.objects.bulk_create([
  841. PortMapping(
  842. device=self.device,
  843. front_port=frontport1_1,
  844. front_port_position=1,
  845. rear_port=rearport1,
  846. rear_port_position=1,
  847. ),
  848. PortMapping(
  849. device=self.device,
  850. front_port=frontport1_2,
  851. front_port_position=1,
  852. rear_port=rearport1,
  853. rear_port_position=2,
  854. ),
  855. PortMapping(
  856. device=self.device,
  857. front_port=frontport2_1,
  858. front_port_position=1,
  859. rear_port=rearport2,
  860. rear_port_position=1,
  861. ),
  862. PortMapping(
  863. device=self.device,
  864. front_port=frontport2_2,
  865. front_port_position=1,
  866. rear_port=rearport2,
  867. rear_port_position=2,
  868. ),
  869. PortMapping(
  870. device=self.device,
  871. front_port=frontport3_1,
  872. front_port_position=1,
  873. rear_port=rearport3,
  874. rear_port_position=1,
  875. ),
  876. PortMapping(
  877. device=self.device,
  878. front_port=frontport3_2,
  879. front_port_position=1,
  880. rear_port=rearport3,
  881. rear_port_position=2,
  882. ),
  883. PortMapping(
  884. device=self.device,
  885. front_port=frontport4_1,
  886. front_port_position=1,
  887. rear_port=rearport4,
  888. rear_port_position=1,
  889. ),
  890. PortMapping(
  891. device=self.device,
  892. front_port=frontport4_2,
  893. front_port_position=1,
  894. rear_port=rearport4,
  895. rear_port_position=2,
  896. ),
  897. ])
  898. # Create cables 1-3, 6-8
  899. cable1 = Cable(
  900. a_terminations=[interface1],
  901. b_terminations=[frontport1_1]
  902. )
  903. cable1.save()
  904. cable2 = Cable(
  905. a_terminations=[interface2],
  906. b_terminations=[frontport1_2]
  907. )
  908. cable2.save()
  909. cable3 = Cable(
  910. a_terminations=[rearport1],
  911. b_terminations=[rearport2]
  912. )
  913. cable3.save()
  914. cable6 = Cable(
  915. a_terminations=[rearport3],
  916. b_terminations=[rearport4]
  917. )
  918. cable6.save()
  919. cable7 = Cable(
  920. a_terminations=[interface3],
  921. b_terminations=[frontport4_1]
  922. )
  923. cable7.save()
  924. cable8 = Cable(
  925. a_terminations=[interface4],
  926. b_terminations=[frontport4_2]
  927. )
  928. cable8.save()
  929. self.assertEqual(CablePath.objects.count(), 4) # Four partial paths; one from each interface
  930. # Create cables 4 and 5
  931. cable4 = Cable(
  932. a_terminations=[frontport2_1],
  933. b_terminations=[frontport3_1]
  934. )
  935. cable4.save()
  936. cable5 = Cable(
  937. a_terminations=[frontport2_2],
  938. b_terminations=[frontport3_2]
  939. )
  940. cable5.save()
  941. self.assertPathExists(
  942. (
  943. interface1, cable1, frontport1_1, rearport1, cable3, rearport2, frontport2_1,
  944. cable4, frontport3_1, rearport3, cable6, rearport4, frontport4_1,
  945. cable7, interface3,
  946. ),
  947. is_complete=True,
  948. is_active=True
  949. )
  950. self.assertPathExists(
  951. (
  952. interface2, cable2, frontport1_2, rearport1, cable3, rearport2, frontport2_2,
  953. cable5, frontport3_2, rearport3, cable6, rearport4, frontport4_2,
  954. cable8, interface4,
  955. ),
  956. is_complete=True,
  957. is_active=True
  958. )
  959. self.assertPathExists(
  960. (
  961. interface3, cable7, frontport4_1, rearport4, cable6, rearport3, frontport3_1,
  962. cable4, frontport2_1, rearport2, cable3, rearport1, frontport1_1,
  963. cable1, interface1,
  964. ),
  965. is_complete=True,
  966. is_active=True
  967. )
  968. self.assertPathExists(
  969. (
  970. interface4, cable8, frontport4_2, rearport4, cable6, rearport3, frontport3_2,
  971. cable5, frontport2_2, rearport2, cable3, rearport1, frontport1_2,
  972. cable2, interface2,
  973. ),
  974. is_complete=True,
  975. is_active=True
  976. )
  977. self.assertEqual(CablePath.objects.count(), 4)
  978. # Test SVG generation
  979. CableTraceSVG(interface1).render()
  980. # Delete cable 5
  981. cable5.delete()
  982. # Check for two complete paths (IF1 <--> IF2) and two partial (IF3 <--> IF4)
  983. self.assertEqual(CablePath.objects.filter(is_complete=False).count(), 2)
  984. self.assertEqual(CablePath.objects.filter(is_complete=True).count(), 2)
  985. def test_207_multiple_paths_via_patched_pass_throughs(self):
  986. """
  987. [IF1] --C1-- [FP1:1] [RP1] --C3-- [FP2] [RP2] --C4-- [RP3] [FP3:1] --C5-- [IF3]
  988. [IF2] --C2-- [FP1:2] [FP3:2] --C6-- [IF4]
  989. """
  990. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  991. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  992. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  993. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  994. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1', positions=4)
  995. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  996. rearport3 = RearPort.objects.create(device=self.device, name='Rear Port 3', positions=4)
  997. frontport1_1 = FrontPort.objects.create(device=self.device, name='Front Port 1:1')
  998. frontport1_2 = FrontPort.objects.create(device=self.device, name='Front Port 1:2')
  999. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  1000. frontport3_1 = FrontPort.objects.create(device=self.device, name='Front Port 3:1')
  1001. frontport3_2 = FrontPort.objects.create(device=self.device, name='Front Port 3:2')
  1002. PortMapping.objects.bulk_create([
  1003. PortMapping(
  1004. device=self.device,
  1005. front_port=frontport1_1,
  1006. front_port_position=1,
  1007. rear_port=rearport1,
  1008. rear_port_position=1,
  1009. ),
  1010. PortMapping(
  1011. device=self.device,
  1012. front_port=frontport1_2,
  1013. front_port_position=1,
  1014. rear_port=rearport1,
  1015. rear_port_position=2,
  1016. ),
  1017. PortMapping(
  1018. device=self.device,
  1019. front_port=frontport2,
  1020. front_port_position=1,
  1021. rear_port=rearport2,
  1022. rear_port_position=1,
  1023. ),
  1024. PortMapping(
  1025. device=self.device,
  1026. front_port=frontport3_1,
  1027. front_port_position=1,
  1028. rear_port=rearport3,
  1029. rear_port_position=1,
  1030. ),
  1031. PortMapping(
  1032. device=self.device,
  1033. front_port=frontport3_2,
  1034. front_port_position=1,
  1035. rear_port=rearport3,
  1036. rear_port_position=2,
  1037. ),
  1038. ])
  1039. # Create cables 1-2, 5-6
  1040. cable1 = Cable(
  1041. a_terminations=[interface1],
  1042. b_terminations=[frontport1_1]
  1043. )
  1044. cable1.save()
  1045. cable2 = Cable(
  1046. a_terminations=[interface2],
  1047. b_terminations=[frontport1_2]
  1048. )
  1049. cable2.save()
  1050. cable5 = Cable(
  1051. a_terminations=[interface3],
  1052. b_terminations=[frontport3_1]
  1053. )
  1054. cable5.save()
  1055. cable6 = Cable(
  1056. a_terminations=[interface4],
  1057. b_terminations=[frontport3_2]
  1058. )
  1059. cable6.save()
  1060. self.assertEqual(CablePath.objects.count(), 4) # Four partial paths; one from each interface
  1061. # Create cables 3-4
  1062. cable3 = Cable(
  1063. a_terminations=[rearport1],
  1064. b_terminations=[frontport2]
  1065. )
  1066. cable3.save()
  1067. cable4 = Cable(
  1068. a_terminations=[rearport2],
  1069. b_terminations=[rearport3]
  1070. )
  1071. cable4.save()
  1072. self.assertPathExists(
  1073. (
  1074. interface1, cable1, frontport1_1, rearport1, cable3, frontport2, rearport2,
  1075. cable4, rearport3, frontport3_1, cable5, interface3,
  1076. ),
  1077. is_complete=True,
  1078. is_active=True
  1079. )
  1080. self.assertPathExists(
  1081. (
  1082. interface2, cable2, frontport1_2, rearport1, cable3, frontport2, rearport2,
  1083. cable4, rearport3, frontport3_2, cable6, interface4,
  1084. ),
  1085. is_complete=True,
  1086. is_active=True
  1087. )
  1088. self.assertPathExists(
  1089. (
  1090. interface3, cable5, frontport3_1, rearport3, cable4, rearport2, frontport2,
  1091. cable3, rearport1, frontport1_1, cable1, interface1,
  1092. ),
  1093. is_complete=True,
  1094. is_active=True
  1095. )
  1096. self.assertPathExists(
  1097. (
  1098. interface4, cable6, frontport3_2, rearport3, cable4, rearport2, frontport2,
  1099. cable3, rearport1, frontport1_2, cable2, interface2,
  1100. ),
  1101. is_complete=True,
  1102. is_active=True
  1103. )
  1104. self.assertEqual(CablePath.objects.count(), 4)
  1105. # Test SVG generation
  1106. CableTraceSVG(interface1).render()
  1107. # Delete cable 3
  1108. cable3.delete()
  1109. # Check for four partial paths; one from each interface
  1110. self.assertEqual(CablePath.objects.filter(is_complete=False).count(), 4)
  1111. self.assertEqual(CablePath.objects.filter(is_complete=True).count(), 0)
  1112. def test_208_unidirectional_split_paths(self):
  1113. """
  1114. [IF1] --C1-- [RP1] [FP1:1] --C2-- [IF2]
  1115. [FP1:2] --C3-- [IF3]
  1116. """
  1117. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1118. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  1119. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  1120. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1', positions=2)
  1121. frontport1_1 = FrontPort.objects.create(device=self.device, name='Front Port 1:1')
  1122. frontport1_2 = FrontPort.objects.create(device=self.device, name='Front Port 1:2')
  1123. PortMapping.objects.bulk_create([
  1124. PortMapping(
  1125. device=self.device,
  1126. front_port=frontport1_1,
  1127. front_port_position=1,
  1128. rear_port=rearport1,
  1129. rear_port_position=1,
  1130. ),
  1131. PortMapping(
  1132. device=self.device,
  1133. front_port=frontport1_2,
  1134. front_port_position=1,
  1135. rear_port=rearport1,
  1136. rear_port_position=2,
  1137. ),
  1138. ])
  1139. # Create cables 1
  1140. cable1 = Cable(
  1141. a_terminations=[interface1],
  1142. b_terminations=[rearport1]
  1143. )
  1144. cable1.save()
  1145. self.assertPathExists(
  1146. (interface1, cable1, rearport1),
  1147. is_complete=False,
  1148. is_split=True
  1149. )
  1150. self.assertEqual(CablePath.objects.count(), 1)
  1151. # Create cables 2-3
  1152. cable2 = Cable(
  1153. a_terminations=[interface2],
  1154. b_terminations=[frontport1_1]
  1155. )
  1156. cable2.save()
  1157. cable3 = Cable(
  1158. a_terminations=[interface3],
  1159. b_terminations=[frontport1_2]
  1160. )
  1161. cable3.save()
  1162. self.assertPathExists(
  1163. (interface2, cable2, frontport1_1, rearport1, cable1, interface1),
  1164. is_complete=True,
  1165. is_active=True
  1166. )
  1167. self.assertPathExists(
  1168. (interface3, cable3, frontport1_2, rearport1, cable1, interface1),
  1169. is_complete=True,
  1170. is_active=True
  1171. )
  1172. self.assertEqual(CablePath.objects.count(), 3)
  1173. # Test SVG generation
  1174. CableTraceSVG(interface1).render()
  1175. # Delete cable 1
  1176. cable1.delete()
  1177. # Check that the partial path was deleted and the two complete paths are now partial
  1178. self.assertPathExists(
  1179. (interface2, cable2, frontport1_1, rearport1),
  1180. is_complete=False
  1181. )
  1182. self.assertPathExists(
  1183. (interface3, cable3, frontport1_2, rearport1),
  1184. is_complete=False
  1185. )
  1186. self.assertEqual(CablePath.objects.count(), 2)
  1187. def test_209_rearport_without_frontport(self):
  1188. """
  1189. [IF1] --C1-- [FP1] [RP1] --C2-- [RP2]
  1190. """
  1191. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1192. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  1193. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  1194. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  1195. PortMapping.objects.create(
  1196. front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1,
  1197. )
  1198. # Create cables
  1199. cable1 = Cable(
  1200. a_terminations=[interface1],
  1201. b_terminations=[frontport1]
  1202. )
  1203. cable1.save()
  1204. cable2 = Cable(
  1205. a_terminations=[rearport1],
  1206. b_terminations=[rearport2]
  1207. )
  1208. cable2.save()
  1209. self.assertPathExists(
  1210. (interface1, cable1, frontport1, rearport1, cable2, rearport2),
  1211. is_complete=False
  1212. )
  1213. self.assertEqual(CablePath.objects.count(), 1)
  1214. # Test SVG generation
  1215. CableTraceSVG(interface1).render()
  1216. def test_210_interface_to_circuittermination(self):
  1217. """
  1218. [IF1] --C1-- [CT1]
  1219. """
  1220. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1221. circuittermination1 = CircuitTermination.objects.create(
  1222. circuit=self.circuit,
  1223. termination=self.site,
  1224. term_side='A'
  1225. )
  1226. # Create cable 1
  1227. cable1 = Cable(
  1228. a_terminations=[interface1],
  1229. b_terminations=[circuittermination1]
  1230. )
  1231. cable1.save()
  1232. # Check for incomplete path
  1233. self.assertPathExists(
  1234. (interface1, cable1, circuittermination1),
  1235. is_complete=False
  1236. )
  1237. self.assertEqual(CablePath.objects.count(), 1)
  1238. # Test SVG generation
  1239. CableTraceSVG(interface1).render()
  1240. # Delete cable 1
  1241. cable1.delete()
  1242. self.assertEqual(CablePath.objects.count(), 0)
  1243. interface1.refresh_from_db()
  1244. self.assertPathIsNotSet(interface1)
  1245. def test_211_interface_to_interface_via_circuit(self):
  1246. """
  1247. [IF1] --C1-- [CT1] [CT2] --C2-- [IF2]
  1248. """
  1249. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1250. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  1251. circuittermination1 = CircuitTermination.objects.create(
  1252. circuit=self.circuit,
  1253. termination=self.site,
  1254. term_side='A'
  1255. )
  1256. # Create cable 1
  1257. cable1 = Cable(
  1258. a_terminations=[interface1],
  1259. b_terminations=[circuittermination1]
  1260. )
  1261. cable1.save()
  1262. # Check for partial path from interface1
  1263. self.assertPathExists(
  1264. (interface1, cable1, circuittermination1),
  1265. is_complete=False
  1266. )
  1267. # Create CT2
  1268. circuittermination2 = CircuitTermination.objects.create(
  1269. circuit=self.circuit,
  1270. termination=self.site,
  1271. term_side='Z'
  1272. )
  1273. # Check for partial path to site
  1274. self.assertPathExists(
  1275. (interface1, cable1, circuittermination1, circuittermination2, self.site),
  1276. is_active=True
  1277. )
  1278. # Create cable 2
  1279. cable2 = Cable(
  1280. a_terminations=[circuittermination2],
  1281. b_terminations=[interface2]
  1282. )
  1283. cable2.save()
  1284. # Check for complete path in each direction
  1285. self.assertPathExists(
  1286. (interface1, cable1, circuittermination1, circuittermination2, cable2, interface2),
  1287. is_complete=True,
  1288. is_active=True
  1289. )
  1290. self.assertPathExists(
  1291. (interface2, cable2, circuittermination2, circuittermination1, cable1, interface1),
  1292. is_complete=True,
  1293. is_active=True
  1294. )
  1295. self.assertEqual(CablePath.objects.count(), 2)
  1296. # Test SVG generation
  1297. CableTraceSVG(interface1).render()
  1298. # Delete cable 2
  1299. cable2.delete()
  1300. path1 = self.assertPathExists(
  1301. (interface1, cable1, circuittermination1, circuittermination2, self.site),
  1302. is_active=True
  1303. )
  1304. self.assertEqual(CablePath.objects.count(), 1)
  1305. interface1.refresh_from_db()
  1306. interface2.refresh_from_db()
  1307. self.assertPathIsSet(interface1, path1)
  1308. self.assertPathIsNotSet(interface2)
  1309. def test_212_interface_to_interface_via_circuit_with_breakouts(self):
  1310. """
  1311. [IF1] --C1-- [CT1] [CT2] --C2-- [IF3]
  1312. [IF2] [IF4]
  1313. """
  1314. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1315. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  1316. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  1317. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  1318. circuittermination1 = CircuitTermination.objects.create(
  1319. circuit=self.circuit,
  1320. termination=self.site,
  1321. term_side='A'
  1322. )
  1323. # Create cable 1
  1324. cable1 = Cable(
  1325. a_terminations=[interface1, interface2],
  1326. b_terminations=[circuittermination1]
  1327. )
  1328. cable1.save()
  1329. # Check for partial path from interface1
  1330. self.assertPathExists(
  1331. ([interface1, interface2], cable1, circuittermination1),
  1332. is_complete=False
  1333. )
  1334. # Create CT2
  1335. circuittermination2 = CircuitTermination.objects.create(
  1336. circuit=self.circuit,
  1337. termination=self.site,
  1338. term_side='Z'
  1339. )
  1340. # Check for partial path to site
  1341. self.assertPathExists(
  1342. ([interface1, interface2], cable1, circuittermination1, circuittermination2, self.site),
  1343. is_active=True
  1344. )
  1345. # Create cable 2
  1346. cable2 = Cable(
  1347. a_terminations=[circuittermination2],
  1348. b_terminations=[interface3, interface4]
  1349. )
  1350. cable2.save()
  1351. # Check for complete path in each direction
  1352. self.assertPathExists(
  1353. (
  1354. [interface1, interface2],
  1355. cable1,
  1356. circuittermination1,
  1357. circuittermination2,
  1358. cable2,
  1359. [interface3, interface4],
  1360. ),
  1361. is_complete=True,
  1362. is_active=True,
  1363. )
  1364. self.assertPathExists(
  1365. (
  1366. [interface3, interface4],
  1367. cable2,
  1368. circuittermination2,
  1369. circuittermination1,
  1370. cable1,
  1371. [interface1, interface2],
  1372. ),
  1373. is_complete=True,
  1374. is_active=True,
  1375. )
  1376. self.assertEqual(CablePath.objects.count(), 2)
  1377. # Test SVG generation
  1378. CableTraceSVG(interface1).render()
  1379. # Delete cable 2
  1380. cable2.delete()
  1381. path1 = self.assertPathExists(
  1382. ([interface1, interface2], cable1, circuittermination1, circuittermination2, self.site),
  1383. is_active=True
  1384. )
  1385. self.assertEqual(CablePath.objects.count(), 1)
  1386. interface1.refresh_from_db()
  1387. interface2.refresh_from_db()
  1388. interface3.refresh_from_db()
  1389. interface4.refresh_from_db()
  1390. self.assertPathIsSet(interface1, path1)
  1391. self.assertPathIsSet(interface2, path1)
  1392. self.assertPathIsNotSet(interface3)
  1393. self.assertPathIsNotSet(interface4)
  1394. def test_213_interface_to_site_via_circuit(self):
  1395. """
  1396. [IF1] --C1-- [CT1] [CT2] --> [Site2]
  1397. """
  1398. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1399. site2 = Site.objects.create(name='Site 2', slug='site-2')
  1400. circuittermination1 = CircuitTermination.objects.create(
  1401. circuit=self.circuit,
  1402. termination=self.site,
  1403. term_side='A'
  1404. )
  1405. circuittermination2 = CircuitTermination.objects.create(
  1406. circuit=self.circuit,
  1407. termination=site2,
  1408. term_side='Z'
  1409. )
  1410. # Create cable 1
  1411. cable1 = Cable(
  1412. a_terminations=[interface1],
  1413. b_terminations=[circuittermination1]
  1414. )
  1415. cable1.save()
  1416. self.assertPathExists(
  1417. (interface1, cable1, circuittermination1, circuittermination2, site2),
  1418. is_active=True
  1419. )
  1420. self.assertEqual(CablePath.objects.count(), 1)
  1421. # Test SVG generation
  1422. CableTraceSVG(interface1).render()
  1423. # Delete cable 1
  1424. cable1.delete()
  1425. self.assertEqual(CablePath.objects.count(), 0)
  1426. interface1.refresh_from_db()
  1427. self.assertPathIsNotSet(interface1)
  1428. def test_214_interface_to_providernetwork_via_circuit(self):
  1429. """
  1430. [IF1] --C1-- [CT1] [CT2] --> [PN1]
  1431. """
  1432. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1433. providernetwork = ProviderNetwork.objects.create(name='Provider Network 1', provider=self.circuit.provider)
  1434. circuittermination1 = CircuitTermination.objects.create(
  1435. circuit=self.circuit,
  1436. termination=self.site,
  1437. term_side='A'
  1438. )
  1439. circuittermination2 = CircuitTermination.objects.create(
  1440. circuit=self.circuit,
  1441. termination=providernetwork,
  1442. term_side='Z'
  1443. )
  1444. # Create cable 1
  1445. cable1 = Cable(
  1446. a_terminations=[interface1],
  1447. b_terminations=[circuittermination1]
  1448. )
  1449. cable1.save()
  1450. self.assertPathExists(
  1451. (interface1, cable1, circuittermination1, circuittermination2, providernetwork),
  1452. is_active=True
  1453. )
  1454. self.assertEqual(CablePath.objects.count(), 1)
  1455. self.assertTrue(CablePath.objects.first().is_complete)
  1456. # Test SVG generation
  1457. CableTraceSVG(interface1).render()
  1458. # Delete cable 1
  1459. cable1.delete()
  1460. self.assertEqual(CablePath.objects.count(), 0)
  1461. interface1.refresh_from_db()
  1462. self.assertPathIsNotSet(interface1)
  1463. def test_215_multiple_paths_via_circuit(self):
  1464. """
  1465. [IF1] --C1-- [FP1:1] [RP1] --C3-- [CT1] [CT2] --C4-- [RP2] [FP2:1] --C5-- [IF3]
  1466. [IF2] --C2-- [FP1:2] [FP2:2] --C6-- [IF4]
  1467. """
  1468. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1469. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  1470. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  1471. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  1472. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1', positions=4)
  1473. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2', positions=4)
  1474. frontport1_1 = FrontPort.objects.create(device=self.device, name='Front Port 1:1')
  1475. frontport1_2 = FrontPort.objects.create(device=self.device, name='Front Port 1:2')
  1476. frontport2_1 = FrontPort.objects.create(device=self.device, name='Front Port 2:1')
  1477. frontport2_2 = FrontPort.objects.create(device=self.device, name='Front Port 2:2')
  1478. PortMapping.objects.bulk_create([
  1479. PortMapping(
  1480. device=self.device,
  1481. front_port=frontport1_1,
  1482. front_port_position=1,
  1483. rear_port=rearport1,
  1484. rear_port_position=1,
  1485. ),
  1486. PortMapping(
  1487. device=self.device,
  1488. front_port=frontport1_2,
  1489. front_port_position=1,
  1490. rear_port=rearport1,
  1491. rear_port_position=2,
  1492. ),
  1493. PortMapping(
  1494. device=self.device,
  1495. front_port=frontport2_1,
  1496. front_port_position=1,
  1497. rear_port=rearport2,
  1498. rear_port_position=1,
  1499. ),
  1500. PortMapping(
  1501. device=self.device,
  1502. front_port=frontport2_2,
  1503. front_port_position=1,
  1504. rear_port=rearport2,
  1505. rear_port_position=2,
  1506. ),
  1507. ])
  1508. circuittermination1 = CircuitTermination.objects.create(
  1509. circuit=self.circuit,
  1510. termination=self.site,
  1511. term_side='A'
  1512. )
  1513. circuittermination2 = CircuitTermination.objects.create(
  1514. circuit=self.circuit,
  1515. termination=self.site, term_side='Z'
  1516. )
  1517. # Create cables
  1518. cable1 = Cable(
  1519. a_terminations=[interface1],
  1520. b_terminations=[frontport1_1]
  1521. )
  1522. cable1.save()
  1523. cable2 = Cable(
  1524. a_terminations=[interface2],
  1525. b_terminations=[frontport1_2]
  1526. )
  1527. cable2.save()
  1528. cable3 = Cable(
  1529. a_terminations=[rearport1],
  1530. b_terminations=[circuittermination1]
  1531. )
  1532. cable3.save()
  1533. cable4 = Cable(
  1534. a_terminations=[rearport2],
  1535. b_terminations=[circuittermination2]
  1536. )
  1537. cable4.save()
  1538. cable5 = Cable(
  1539. a_terminations=[interface3],
  1540. b_terminations=[frontport2_1]
  1541. )
  1542. cable5.save()
  1543. cable6 = Cable(
  1544. a_terminations=[interface4],
  1545. b_terminations=[frontport2_2]
  1546. )
  1547. cable6.save()
  1548. self.assertPathExists(
  1549. (
  1550. interface1, cable1, frontport1_1, rearport1, cable3, circuittermination1, circuittermination2,
  1551. cable4, rearport2, frontport2_1, cable5, interface3,
  1552. ),
  1553. is_complete=True,
  1554. is_active=True
  1555. )
  1556. self.assertPathExists(
  1557. (
  1558. interface2, cable2, frontport1_2, rearport1, cable3, circuittermination1, circuittermination2,
  1559. cable4, rearport2, frontport2_2, cable6, interface4,
  1560. ),
  1561. is_complete=True,
  1562. is_active=True
  1563. )
  1564. self.assertPathExists(
  1565. (
  1566. interface3, cable5, frontport2_1, rearport2, cable4, circuittermination2, circuittermination1,
  1567. cable3, rearport1, frontport1_1, cable1, interface1,
  1568. ),
  1569. is_complete=True,
  1570. is_active=True
  1571. )
  1572. self.assertPathExists(
  1573. (
  1574. interface4, cable6, frontport2_2, rearport2, cable4, circuittermination2, circuittermination1,
  1575. cable3, rearport1, frontport1_2, cable2, interface2,
  1576. ),
  1577. is_complete=True,
  1578. is_active=True
  1579. )
  1580. self.assertEqual(CablePath.objects.count(), 4)
  1581. # Test SVG generation
  1582. CableTraceSVG(interface1).render()
  1583. # Delete cables 3-4
  1584. cable3.delete()
  1585. cable4.delete()
  1586. # Check for four partial paths; one from each interface
  1587. self.assertEqual(CablePath.objects.filter(is_complete=False).count(), 4)
  1588. self.assertEqual(CablePath.objects.filter(is_complete=True).count(), 0)
  1589. def test_216_interface_to_interface_via_multiple_circuits(self):
  1590. """
  1591. [IF1] --C1-- [CT1] [CT2] --C2-- [CT3] [CT4] --C3-- [IF2]
  1592. """
  1593. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1594. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  1595. circuit2 = Circuit.objects.create(provider=self.circuit.provider, type=self.circuit.type, cid='Circuit 2')
  1596. circuittermination1 = CircuitTermination.objects.create(
  1597. circuit=self.circuit,
  1598. termination=self.site,
  1599. term_side='A'
  1600. )
  1601. circuittermination2 = CircuitTermination.objects.create(
  1602. circuit=self.circuit,
  1603. termination=self.site,
  1604. term_side='Z'
  1605. )
  1606. circuittermination3 = CircuitTermination.objects.create(
  1607. circuit=circuit2,
  1608. termination=self.site,
  1609. term_side='A'
  1610. )
  1611. circuittermination4 = CircuitTermination.objects.create(
  1612. circuit=circuit2,
  1613. termination=self.site,
  1614. term_side='Z'
  1615. )
  1616. # Create cables
  1617. cable1 = Cable(
  1618. a_terminations=[interface1],
  1619. b_terminations=[circuittermination1]
  1620. )
  1621. cable1.save()
  1622. cable2 = Cable(
  1623. a_terminations=[circuittermination2],
  1624. b_terminations=[circuittermination3]
  1625. )
  1626. cable2.save()
  1627. cable3 = Cable(
  1628. a_terminations=[circuittermination4],
  1629. b_terminations=[interface2]
  1630. )
  1631. cable3.save()
  1632. # Check for paths
  1633. self.assertPathExists(
  1634. (
  1635. interface1, cable1, circuittermination1, circuittermination2, cable2, circuittermination3,
  1636. circuittermination4, cable3, interface2,
  1637. ),
  1638. is_complete=True,
  1639. is_active=True
  1640. )
  1641. self.assertPathExists(
  1642. (
  1643. interface2, cable3, circuittermination4, circuittermination3, cable2, circuittermination2,
  1644. circuittermination1, cable1, interface1,
  1645. ),
  1646. is_complete=True,
  1647. is_active=True
  1648. )
  1649. self.assertEqual(CablePath.objects.count(), 2)
  1650. # Test SVG generation
  1651. CableTraceSVG(interface1).render()
  1652. # Delete cable 2
  1653. cable2.delete()
  1654. path1 = self.assertPathExists(
  1655. (interface1, cable1, circuittermination1, circuittermination2, self.site),
  1656. is_active=True
  1657. )
  1658. path2 = self.assertPathExists(
  1659. (interface2, cable3, circuittermination4, circuittermination3, self.site),
  1660. is_active=True
  1661. )
  1662. self.assertEqual(CablePath.objects.count(), 2)
  1663. interface1.refresh_from_db()
  1664. interface2.refresh_from_db()
  1665. self.assertPathIsSet(interface1, path1)
  1666. self.assertPathIsSet(interface2, path2)
  1667. def test_217_interface_to_interface_via_rear_ports(self):
  1668. """
  1669. [IF1] --C1-- [FP1] [RP1] --C2-- [RP3] [FP3] --C3-- [IF2]
  1670. [FP2] [RP2] [RP4] [FP4]
  1671. """
  1672. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1673. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  1674. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  1675. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  1676. rearport3 = RearPort.objects.create(device=self.device, name='Rear Port 3')
  1677. rearport4 = RearPort.objects.create(device=self.device, name='Rear Port 4')
  1678. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  1679. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  1680. frontport3 = FrontPort.objects.create(device=self.device, name='Front Port 3')
  1681. frontport4 = FrontPort.objects.create(device=self.device, name='Front Port 4')
  1682. PortMapping.objects.bulk_create([
  1683. PortMapping(
  1684. device=self.device,
  1685. front_port=frontport1,
  1686. front_port_position=1,
  1687. rear_port=rearport1,
  1688. rear_port_position=1,
  1689. ),
  1690. PortMapping(
  1691. device=self.device,
  1692. front_port=frontport2,
  1693. front_port_position=1,
  1694. rear_port=rearport2,
  1695. rear_port_position=1,
  1696. ),
  1697. PortMapping(
  1698. device=self.device,
  1699. front_port=frontport3,
  1700. front_port_position=1,
  1701. rear_port=rearport3,
  1702. rear_port_position=1,
  1703. ),
  1704. PortMapping(
  1705. device=self.device,
  1706. front_port=frontport4,
  1707. front_port_position=1,
  1708. rear_port=rearport4,
  1709. rear_port_position=1,
  1710. ),
  1711. ])
  1712. # Create cables 1-2
  1713. cable1 = Cable(
  1714. a_terminations=[interface1],
  1715. b_terminations=[frontport1, frontport2]
  1716. )
  1717. cable1.save()
  1718. cable3 = Cable(
  1719. a_terminations=[interface2],
  1720. b_terminations=[frontport3, frontport4]
  1721. )
  1722. cable3.save()
  1723. self.assertPathExists(
  1724. (interface1, cable1, (frontport1, frontport2), (rearport1, rearport2)),
  1725. is_complete=False
  1726. )
  1727. self.assertPathExists(
  1728. (interface2, cable3, (frontport3, frontport4), (rearport3, rearport4)),
  1729. is_complete=False
  1730. )
  1731. self.assertEqual(CablePath.objects.count(), 2)
  1732. # Create cable 2
  1733. cable2 = Cable(
  1734. a_terminations=[rearport1, rearport2],
  1735. b_terminations=[rearport3, rearport4]
  1736. )
  1737. cable2.save()
  1738. path1 = self.assertPathExists(
  1739. (
  1740. interface1, cable1, (frontport1, frontport2), (rearport1, rearport2), cable2,
  1741. (rearport3, rearport4), (frontport3, frontport4), cable3, interface2
  1742. ),
  1743. is_complete=True
  1744. )
  1745. path2 = self.assertPathExists(
  1746. (
  1747. interface2, cable3, (frontport3, frontport4), (rearport3, rearport4), cable2,
  1748. (rearport1, rearport2), (frontport1, frontport2), cable1, interface1
  1749. ),
  1750. is_complete=True
  1751. )
  1752. self.assertEqual(CablePath.objects.count(), 2)
  1753. # Test SVG generation
  1754. CableTraceSVG(interface1).render()
  1755. # Delete cable 2
  1756. cable2.delete()
  1757. # Check for two partial paths; one from each interface
  1758. self.assertEqual(CablePath.objects.filter(is_complete=False).count(), 2)
  1759. self.assertEqual(CablePath.objects.filter(is_complete=True).count(), 0)
  1760. interface1.refresh_from_db()
  1761. interface2.refresh_from_db()
  1762. self.assertPathIsSet(interface1, path1)
  1763. self.assertPathIsSet(interface2, path2)
  1764. def test_218_interfaces_to_interfaces_via_multiposition_rear_ports(self):
  1765. """
  1766. [IF1] --C1-- [FP1:1] [RP1] --C3-- [RP2] [FP2:1] --C4-- [IF3]
  1767. [FP1:2] [FP2:2]
  1768. [IF2] --C2-- [FP1:3] [FP2:3] --C5-- [IF4]
  1769. [FP1:4] [FP2:4]
  1770. """
  1771. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1772. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  1773. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  1774. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  1775. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1', positions=4)
  1776. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2', positions=4)
  1777. frontport1_1 = FrontPort.objects.create(device=self.device, name='Front Port 1:1')
  1778. frontport1_2 = FrontPort.objects.create(device=self.device, name='Front Port 1:2')
  1779. frontport1_3 = FrontPort.objects.create(device=self.device, name='Front Port 1:3')
  1780. frontport1_4 = FrontPort.objects.create(device=self.device, name='Front Port 1:4')
  1781. frontport2_1 = FrontPort.objects.create(device=self.device, name='Front Port 2:1')
  1782. frontport2_2 = FrontPort.objects.create(device=self.device, name='Front Port 2:2')
  1783. frontport2_3 = FrontPort.objects.create(device=self.device, name='Front Port 2:3')
  1784. frontport2_4 = FrontPort.objects.create(device=self.device, name='Front Port 2:4')
  1785. PortMapping.objects.bulk_create([
  1786. PortMapping(
  1787. device=self.device,
  1788. front_port=frontport1_1,
  1789. front_port_position=1,
  1790. rear_port=rearport1,
  1791. rear_port_position=1,
  1792. ),
  1793. PortMapping(
  1794. device=self.device,
  1795. front_port=frontport1_2,
  1796. front_port_position=1,
  1797. rear_port=rearport1,
  1798. rear_port_position=2,
  1799. ),
  1800. PortMapping(
  1801. device=self.device,
  1802. front_port=frontport1_3,
  1803. front_port_position=1,
  1804. rear_port=rearport1,
  1805. rear_port_position=3,
  1806. ),
  1807. PortMapping(
  1808. device=self.device,
  1809. front_port=frontport1_4,
  1810. front_port_position=1,
  1811. rear_port=rearport1,
  1812. rear_port_position=4,
  1813. ),
  1814. PortMapping(
  1815. device=self.device,
  1816. front_port=frontport2_1,
  1817. front_port_position=1,
  1818. rear_port=rearport2,
  1819. rear_port_position=1,
  1820. ),
  1821. PortMapping(
  1822. device=self.device,
  1823. front_port=frontport2_2,
  1824. front_port_position=1,
  1825. rear_port=rearport2,
  1826. rear_port_position=2,
  1827. ),
  1828. PortMapping(
  1829. device=self.device,
  1830. front_port=frontport2_3,
  1831. front_port_position=1,
  1832. rear_port=rearport2,
  1833. rear_port_position=3,
  1834. ),
  1835. PortMapping(
  1836. device=self.device,
  1837. front_port=frontport2_4,
  1838. front_port_position=1,
  1839. rear_port=rearport2,
  1840. rear_port_position=4,
  1841. ),
  1842. ])
  1843. # Create cables 1-2
  1844. cable1 = Cable(
  1845. a_terminations=[interface1],
  1846. b_terminations=[frontport1_1, frontport1_2]
  1847. )
  1848. cable1.save()
  1849. cable2 = Cable(
  1850. a_terminations=[interface2],
  1851. b_terminations=[frontport1_3, frontport1_4]
  1852. )
  1853. cable2.save()
  1854. self.assertPathExists(
  1855. (interface1, cable1, (frontport1_1, frontport1_2), rearport1),
  1856. is_complete=False
  1857. )
  1858. self.assertPathExists(
  1859. (interface2, cable2, (frontport1_3, frontport1_4), rearport1),
  1860. is_complete=False
  1861. )
  1862. self.assertEqual(CablePath.objects.count(), 2)
  1863. # Create cable 3
  1864. cable3 = Cable(
  1865. a_terminations=[rearport1],
  1866. b_terminations=[rearport2]
  1867. )
  1868. cable3.save()
  1869. self.assertPathExists(
  1870. (
  1871. interface1,
  1872. cable1,
  1873. (frontport1_1, frontport1_2),
  1874. rearport1,
  1875. cable3,
  1876. rearport2,
  1877. (frontport2_1, frontport2_2),
  1878. ),
  1879. is_complete=False,
  1880. )
  1881. self.assertPathExists(
  1882. (
  1883. interface2,
  1884. cable2,
  1885. (frontport1_3, frontport1_4),
  1886. rearport1,
  1887. cable3,
  1888. rearport2,
  1889. (frontport2_3, frontport2_4),
  1890. ),
  1891. is_complete=False,
  1892. )
  1893. self.assertEqual(CablePath.objects.count(), 2)
  1894. # Create cables 4-5
  1895. cable4 = Cable(a_terminations=[frontport2_1, frontport2_2], b_terminations=[interface3])
  1896. cable4.save()
  1897. cable5 = Cable(a_terminations=[frontport2_3, frontport2_4], b_terminations=[interface4])
  1898. cable5.save()
  1899. path1 = self.assertPathExists(
  1900. (
  1901. interface1,
  1902. cable1,
  1903. (frontport1_1, frontport1_2),
  1904. rearport1,
  1905. cable3,
  1906. rearport2,
  1907. (frontport2_1, frontport2_2),
  1908. cable4,
  1909. interface3,
  1910. ),
  1911. is_complete=True,
  1912. is_active=True,
  1913. )
  1914. path2 = self.assertPathExists(
  1915. (
  1916. interface2,
  1917. cable2,
  1918. (frontport1_3, frontport1_4),
  1919. rearport1,
  1920. cable3,
  1921. rearport2,
  1922. (frontport2_3, frontport2_4),
  1923. cable5,
  1924. interface4,
  1925. ),
  1926. is_complete=True,
  1927. is_active=True,
  1928. )
  1929. path3 = self.assertPathExists(
  1930. (
  1931. interface3,
  1932. cable4,
  1933. (frontport2_1, frontport2_2),
  1934. rearport2,
  1935. cable3,
  1936. rearport1,
  1937. (frontport1_1, frontport1_2),
  1938. cable1,
  1939. interface1,
  1940. ),
  1941. is_complete=True,
  1942. is_active=True,
  1943. )
  1944. path4 = self.assertPathExists(
  1945. (
  1946. interface4,
  1947. cable5,
  1948. (frontport2_3, frontport2_4),
  1949. rearport2,
  1950. cable3,
  1951. rearport1,
  1952. (frontport1_3, frontport1_4),
  1953. cable2,
  1954. interface2,
  1955. ),
  1956. is_complete=True,
  1957. is_active=True,
  1958. )
  1959. self.assertEqual(CablePath.objects.count(), 4)
  1960. # Test SVG generation
  1961. CableTraceSVG(interface1).render()
  1962. # Delete cable 3
  1963. cable3.delete()
  1964. # Check for four partial paths; one from each interface
  1965. self.assertEqual(CablePath.objects.filter(is_complete=False).count(), 4)
  1966. self.assertEqual(CablePath.objects.filter(is_complete=True).count(), 0)
  1967. interface1.refresh_from_db()
  1968. interface2.refresh_from_db()
  1969. interface3.refresh_from_db()
  1970. interface4.refresh_from_db()
  1971. self.assertPathIsSet(interface1, path1)
  1972. self.assertPathIsSet(interface2, path2)
  1973. self.assertPathIsSet(interface3, path3)
  1974. self.assertPathIsSet(interface4, path4)
  1975. def test_219_interface_to_interface_duplex_via_multiple_rearports(self):
  1976. """
  1977. [IF1] --C1-- [FP1] [RP1] --C2-- [RP2] [FP2] --C3-- [IF2]
  1978. [FP3] [RP3] --C4-- [RP4] [FP4]
  1979. """
  1980. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  1981. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  1982. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  1983. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  1984. rearport3 = RearPort.objects.create(device=self.device, name='Rear Port 3')
  1985. rearport4 = RearPort.objects.create(device=self.device, name='Rear Port 4')
  1986. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  1987. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  1988. frontport3 = FrontPort.objects.create(device=self.device, name='Front Port 3')
  1989. frontport4 = FrontPort.objects.create(device=self.device, name='Front Port 4')
  1990. PortMapping.objects.bulk_create([
  1991. PortMapping(
  1992. device=self.device,
  1993. front_port=frontport1,
  1994. front_port_position=1,
  1995. rear_port=rearport1,
  1996. rear_port_position=1,
  1997. ),
  1998. PortMapping(
  1999. device=self.device,
  2000. front_port=frontport2,
  2001. front_port_position=1,
  2002. rear_port=rearport2,
  2003. rear_port_position=1,
  2004. ),
  2005. PortMapping(
  2006. device=self.device,
  2007. front_port=frontport3,
  2008. front_port_position=1,
  2009. rear_port=rearport3,
  2010. rear_port_position=1,
  2011. ),
  2012. PortMapping(
  2013. device=self.device,
  2014. front_port=frontport4,
  2015. front_port_position=1,
  2016. rear_port=rearport4,
  2017. rear_port_position=1,
  2018. ),
  2019. ])
  2020. cable2 = Cable(
  2021. a_terminations=[rearport1],
  2022. b_terminations=[rearport2]
  2023. )
  2024. cable2.save()
  2025. cable4 = Cable(
  2026. a_terminations=[rearport3],
  2027. b_terminations=[rearport4]
  2028. )
  2029. cable4.save()
  2030. self.assertEqual(CablePath.objects.count(), 0)
  2031. # Create cable1
  2032. cable1 = Cable(
  2033. a_terminations=[interface1],
  2034. b_terminations=[frontport1, frontport3]
  2035. )
  2036. cable1.save()
  2037. self.assertPathExists(
  2038. (
  2039. interface1, cable1, (frontport1, frontport3), (rearport1, rearport3), (cable2, cable4),
  2040. (rearport2, rearport4), (frontport2, frontport4)
  2041. ),
  2042. is_complete=False
  2043. )
  2044. self.assertEqual(CablePath.objects.count(), 1)
  2045. # Create cable 3
  2046. cable3 = Cable(
  2047. a_terminations=[frontport2, frontport4],
  2048. b_terminations=[interface2]
  2049. )
  2050. cable3.save()
  2051. self.assertPathExists(
  2052. (
  2053. interface1, cable1, (frontport1, frontport3), (rearport1, rearport3), (cable2, cable4),
  2054. (rearport2, rearport4), (frontport2, frontport4), cable3, interface2
  2055. ),
  2056. is_complete=True,
  2057. is_active=True
  2058. )
  2059. self.assertPathExists(
  2060. (
  2061. interface2, cable3, (frontport2, frontport4), (rearport2, rearport4), (cable2, cable4),
  2062. (rearport1, rearport3), (frontport1, frontport3), cable1, interface1
  2063. ),
  2064. is_complete=True,
  2065. is_active=True
  2066. )
  2067. self.assertEqual(CablePath.objects.count(), 2)
  2068. # Test SVG generation
  2069. CableTraceSVG(interface1).render()
  2070. def test_220_interface_to_interface_duplex_via_multiple_front_and_rear_ports(self):
  2071. """
  2072. [IF1] --C1-- [FP1] [RP1] --C2-- [RP2] [FP2] --C3-- [IF2]
  2073. [IF2] --C5-- [FP3] [RP3] --C4-- [RP4] [FP4]
  2074. """
  2075. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2076. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2077. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  2078. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  2079. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  2080. rearport3 = RearPort.objects.create(device=self.device, name='Rear Port 3')
  2081. rearport4 = RearPort.objects.create(device=self.device, name='Rear Port 4')
  2082. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  2083. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  2084. frontport3 = FrontPort.objects.create(device=self.device, name='Front Port 3')
  2085. frontport4 = FrontPort.objects.create(device=self.device, name='Front Port 4')
  2086. PortMapping.objects.bulk_create([
  2087. PortMapping(
  2088. device=self.device,
  2089. front_port=frontport1,
  2090. front_port_position=1,
  2091. rear_port=rearport1,
  2092. rear_port_position=1,
  2093. ),
  2094. PortMapping(
  2095. device=self.device,
  2096. front_port=frontport2,
  2097. front_port_position=1,
  2098. rear_port=rearport2,
  2099. rear_port_position=1,
  2100. ),
  2101. PortMapping(
  2102. device=self.device,
  2103. front_port=frontport3,
  2104. front_port_position=1,
  2105. rear_port=rearport3,
  2106. rear_port_position=1,
  2107. ),
  2108. PortMapping(
  2109. device=self.device,
  2110. front_port=frontport4,
  2111. front_port_position=1,
  2112. rear_port=rearport4,
  2113. rear_port_position=1,
  2114. ),
  2115. ])
  2116. cable2 = Cable(
  2117. a_terminations=[rearport1],
  2118. b_terminations=[rearport2]
  2119. )
  2120. cable2.save()
  2121. cable4 = Cable(
  2122. a_terminations=[rearport3],
  2123. b_terminations=[rearport4]
  2124. )
  2125. cable4.save()
  2126. self.assertEqual(CablePath.objects.count(), 0)
  2127. # Create cable1
  2128. cable1 = Cable(
  2129. a_terminations=[interface1],
  2130. b_terminations=[frontport1]
  2131. )
  2132. cable1.save()
  2133. self.assertPathExists(
  2134. (
  2135. interface1, cable1, frontport1, rearport1, cable2, rearport2, frontport2
  2136. ),
  2137. is_complete=False
  2138. )
  2139. # Create cable1
  2140. cable5 = Cable(
  2141. a_terminations=[interface3],
  2142. b_terminations=[frontport3]
  2143. )
  2144. cable5.save()
  2145. self.assertPathExists(
  2146. (
  2147. interface3, cable5, frontport3, rearport3, cable4, rearport4, frontport4
  2148. ),
  2149. is_complete=False
  2150. )
  2151. self.assertEqual(CablePath.objects.count(), 2)
  2152. # Create cable 3
  2153. cable3 = Cable(
  2154. a_terminations=[frontport2, frontport4],
  2155. b_terminations=[interface2]
  2156. )
  2157. cable3.save()
  2158. self.assertPathExists(
  2159. (
  2160. interface2, cable3, (frontport2, frontport4), (rearport2, rearport4), (cable2, cable4),
  2161. (rearport1, rearport3), (frontport1, frontport3), (cable1, cable5), (interface1, interface3)
  2162. ),
  2163. is_complete=True,
  2164. is_active=True
  2165. )
  2166. self.assertPathExists(
  2167. (
  2168. interface1, cable1, frontport1, rearport1, cable2, rearport2, frontport2, cable3, interface2
  2169. ),
  2170. is_complete=True,
  2171. is_active=True
  2172. )
  2173. self.assertPathExists(
  2174. (
  2175. interface3, cable5, frontport3, rearport3, cable4, rearport4, frontport4, cable3, interface2
  2176. ),
  2177. is_complete=True,
  2178. is_active=True
  2179. )
  2180. self.assertEqual(CablePath.objects.count(), 3)
  2181. # Test SVG generation
  2182. CableTraceSVG(interface1).render()
  2183. def test_221_non_symmetric_paths(self):
  2184. """
  2185. [IF1] --C1-- [FP1] [RP1] --C2-- [RP2] [FP2] --C3-- -------------------------------------- [IF2]
  2186. [IF2] --C5-- [FP3] [RP3] --C4-- [RP4] [FP4] --C6-- [FP5] [RP5] --C7-- [RP6] [FP6] --C3---/
  2187. """
  2188. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2189. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2190. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  2191. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  2192. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  2193. rearport3 = RearPort.objects.create(device=self.device, name='Rear Port 3')
  2194. rearport4 = RearPort.objects.create(device=self.device, name='Rear Port 4')
  2195. rearport5 = RearPort.objects.create(device=self.device, name='Rear Port 5')
  2196. rearport6 = RearPort.objects.create(device=self.device, name='Rear Port 6')
  2197. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  2198. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  2199. frontport3 = FrontPort.objects.create(device=self.device, name='Front Port 3')
  2200. frontport4 = FrontPort.objects.create(device=self.device, name='Front Port 4')
  2201. frontport5 = FrontPort.objects.create(device=self.device, name='Front Port 5')
  2202. frontport6 = FrontPort.objects.create(device=self.device, name='Front Port 6')
  2203. PortMapping.objects.bulk_create([
  2204. PortMapping(
  2205. device=self.device,
  2206. front_port=frontport1,
  2207. front_port_position=1,
  2208. rear_port=rearport1,
  2209. rear_port_position=1,
  2210. ),
  2211. PortMapping(
  2212. device=self.device,
  2213. front_port=frontport2,
  2214. front_port_position=1,
  2215. rear_port=rearport2,
  2216. rear_port_position=1,
  2217. ),
  2218. PortMapping(
  2219. device=self.device,
  2220. front_port=frontport3,
  2221. front_port_position=1,
  2222. rear_port=rearport3,
  2223. rear_port_position=1,
  2224. ),
  2225. PortMapping(
  2226. device=self.device,
  2227. front_port=frontport4,
  2228. front_port_position=1,
  2229. rear_port=rearport4,
  2230. rear_port_position=1,
  2231. ),
  2232. PortMapping(
  2233. device=self.device,
  2234. front_port=frontport5,
  2235. front_port_position=1,
  2236. rear_port=rearport5,
  2237. rear_port_position=1,
  2238. ),
  2239. PortMapping(
  2240. device=self.device,
  2241. front_port=frontport6,
  2242. front_port_position=1,
  2243. rear_port=rearport6,
  2244. rear_port_position=1,
  2245. ),
  2246. ])
  2247. cable2 = Cable(
  2248. a_terminations=[rearport1],
  2249. b_terminations=[rearport2],
  2250. label='C2'
  2251. )
  2252. cable2.save()
  2253. cable4 = Cable(
  2254. a_terminations=[rearport3],
  2255. b_terminations=[rearport4],
  2256. label='C4'
  2257. )
  2258. cable4.save()
  2259. cable6 = Cable(
  2260. a_terminations=[frontport4],
  2261. b_terminations=[frontport5],
  2262. label='C6'
  2263. )
  2264. cable6.save()
  2265. cable7 = Cable(
  2266. a_terminations=[rearport5],
  2267. b_terminations=[rearport6],
  2268. label='C7'
  2269. )
  2270. cable7.save()
  2271. self.assertEqual(CablePath.objects.count(), 0)
  2272. # Create cable1
  2273. cable1 = Cable(
  2274. a_terminations=[interface1],
  2275. b_terminations=[frontport1],
  2276. label='C1'
  2277. )
  2278. cable1.save()
  2279. self.assertPathExists(
  2280. (
  2281. interface1, cable1, frontport1, rearport1, cable2, rearport2, frontport2
  2282. ),
  2283. is_complete=False
  2284. )
  2285. # Create cable1
  2286. cable5 = Cable(
  2287. a_terminations=[interface3],
  2288. b_terminations=[frontport3],
  2289. label='C5'
  2290. )
  2291. cable5.save()
  2292. self.assertPathExists(
  2293. (
  2294. interface3, cable5, frontport3, rearport3, cable4, rearport4, frontport4, cable6, frontport5, rearport5,
  2295. cable7, rearport6, frontport6
  2296. ),
  2297. is_complete=False
  2298. )
  2299. self.assertEqual(CablePath.objects.count(), 2)
  2300. # Create cable 3
  2301. cable3 = Cable(
  2302. a_terminations=[frontport2, frontport6],
  2303. b_terminations=[interface2],
  2304. label='C3'
  2305. )
  2306. cable3.save()
  2307. self.assertPathExists(
  2308. (
  2309. interface2, cable3, (frontport2, frontport6), (rearport2, rearport6), (cable2, cable7),
  2310. (rearport1, rearport5), (frontport1, frontport5), (cable1, cable6)
  2311. ),
  2312. is_complete=False,
  2313. is_split=True
  2314. )
  2315. self.assertPathExists(
  2316. (
  2317. interface1, cable1, frontport1, rearport1, cable2, rearport2, frontport2, cable3, interface2
  2318. ),
  2319. is_complete=True,
  2320. is_active=True
  2321. )
  2322. self.assertPathExists(
  2323. (
  2324. interface3, cable5, frontport3, rearport3, cable4, rearport4, frontport4, cable6, frontport5, rearport5,
  2325. cable7, rearport6, frontport6, cable3, interface2
  2326. ),
  2327. is_complete=True,
  2328. is_active=True
  2329. )
  2330. self.assertEqual(CablePath.objects.count(), 3)
  2331. # Test SVG generation
  2332. CableTraceSVG(interface1).render()
  2333. def test_222_single_path_via_multiple_singleposition_rear_ports(self):
  2334. """
  2335. [IF1] --C1-- [FP1] [RP1] --C2-- [IF2]
  2336. [FP2] [RP2]
  2337. """
  2338. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2339. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2340. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  2341. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  2342. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  2343. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  2344. PortMapping.objects.bulk_create([
  2345. PortMapping(
  2346. device=self.device,
  2347. front_port=frontport1,
  2348. front_port_position=1,
  2349. rear_port=rearport1,
  2350. rear_port_position=1,
  2351. ),
  2352. PortMapping(
  2353. device=self.device,
  2354. front_port=frontport2,
  2355. front_port_position=1,
  2356. rear_port=rearport2,
  2357. rear_port_position=1,
  2358. ),
  2359. ])
  2360. cable1 = Cable(
  2361. a_terminations=[interface1],
  2362. b_terminations=[frontport1, frontport2]
  2363. )
  2364. cable1.save()
  2365. self.assertEqual(CablePath.objects.count(), 1)
  2366. cable2 = Cable(
  2367. a_terminations=[rearport1, rearport2],
  2368. b_terminations=[interface2]
  2369. )
  2370. cable2.save()
  2371. self.assertEqual(CablePath.objects.count(), 2)
  2372. self.assertPathExists(
  2373. (interface1, cable1, (frontport1, frontport2), (rearport1, rearport2), cable2, interface2),
  2374. is_complete=True
  2375. )
  2376. self.assertPathExists(
  2377. (interface2, cable2, (rearport1, rearport2), (frontport1, frontport2), cable1, interface1),
  2378. is_complete=True
  2379. )
  2380. # Test SVG generation both directions
  2381. CableTraceSVG(interface1).render()
  2382. CableTraceSVG(interface2).render()
  2383. def test_223_interface_to_interface_via_multiple_circuit_terminations(self):
  2384. provider = Provider.objects.first()
  2385. circuit_type = CircuitType.objects.first()
  2386. circuit1 = self.circuit
  2387. circuit2 = Circuit.objects.create(provider=provider, type=circuit_type, cid='Circuit 2')
  2388. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2389. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2390. circuittermination1_A = CircuitTermination.objects.create(
  2391. circuit=circuit1,
  2392. termination=self.site,
  2393. term_side='A'
  2394. )
  2395. circuittermination1_Z = CircuitTermination.objects.create(
  2396. circuit=circuit1,
  2397. termination=self.site,
  2398. term_side='Z'
  2399. )
  2400. circuittermination2_A = CircuitTermination.objects.create(
  2401. circuit=circuit2,
  2402. termination=self.site,
  2403. term_side='A'
  2404. )
  2405. circuittermination2_Z = CircuitTermination.objects.create(
  2406. circuit=circuit2,
  2407. termination=self.site,
  2408. term_side='Z'
  2409. )
  2410. # Create cables
  2411. cable1 = Cable(
  2412. a_terminations=[interface1],
  2413. b_terminations=[circuittermination1_A, circuittermination2_A]
  2414. )
  2415. cable2 = Cable(
  2416. a_terminations=[interface2],
  2417. b_terminations=[circuittermination1_Z, circuittermination2_Z]
  2418. )
  2419. cable1.save()
  2420. cable2.save()
  2421. self.assertEqual(CablePath.objects.count(), 2)
  2422. path1 = self.assertPathExists(
  2423. (
  2424. interface1,
  2425. cable1,
  2426. (circuittermination1_A, circuittermination2_A),
  2427. (circuittermination1_Z, circuittermination2_Z),
  2428. cable2,
  2429. interface2
  2430. ),
  2431. is_active=True,
  2432. is_complete=True,
  2433. )
  2434. interface1.refresh_from_db()
  2435. self.assertPathIsSet(interface1, path1)
  2436. path2 = self.assertPathExists(
  2437. (
  2438. interface2,
  2439. cable2,
  2440. (circuittermination1_Z, circuittermination2_Z),
  2441. (circuittermination1_A, circuittermination2_A),
  2442. cable1,
  2443. interface1
  2444. ),
  2445. is_active=True,
  2446. is_complete=True,
  2447. )
  2448. interface2.refresh_from_db()
  2449. self.assertPathIsSet(interface2, path2)
  2450. def test_224_single_path_via_multiple_pass_throughs_with_breakouts(self):
  2451. """
  2452. [IF1] --C1-- [FP1] [RP1] --C2-- [IF3]
  2453. [IF2] [FP2] [RP2] [IF4]
  2454. """
  2455. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2456. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2457. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  2458. interface4 = Interface.objects.create(device=self.device, name='Interface 4')
  2459. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  2460. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  2461. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  2462. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  2463. PortMapping.objects.bulk_create([
  2464. PortMapping(
  2465. device=self.device,
  2466. front_port=frontport1,
  2467. front_port_position=1,
  2468. rear_port=rearport1,
  2469. rear_port_position=1,
  2470. ),
  2471. PortMapping(
  2472. device=self.device,
  2473. front_port=frontport2,
  2474. front_port_position=1,
  2475. rear_port=rearport2,
  2476. rear_port_position=1,
  2477. ),
  2478. ])
  2479. # Create cables
  2480. cable1 = Cable(
  2481. a_terminations=[interface1, interface2],
  2482. b_terminations=[frontport1, frontport2]
  2483. )
  2484. cable1.save()
  2485. cable2 = Cable(
  2486. a_terminations=[rearport1, rearport2],
  2487. b_terminations=[interface3, interface4]
  2488. )
  2489. cable2.save()
  2490. # Validate paths
  2491. self.assertPathExists(
  2492. (
  2493. [interface1, interface2], cable1, [frontport1, frontport2],
  2494. [rearport1, rearport2], cable2, [interface3, interface4],
  2495. ),
  2496. is_complete=True,
  2497. is_active=True
  2498. )
  2499. self.assertPathExists(
  2500. (
  2501. [interface3, interface4], cable2, [rearport1, rearport2],
  2502. [frontport1, frontport2], cable1, [interface1, interface2],
  2503. ),
  2504. is_complete=True,
  2505. is_active=True
  2506. )
  2507. self.assertEqual(CablePath.objects.count(), 2)
  2508. def test_225_circuittermination_origin_passive_network(self):
  2509. """
  2510. [CT1] --C1-- [RP1] [FP1]
  2511. A CircuitTermination cabled into a passive (FrontPort/RearPort-only) device can become a
  2512. CablePath origin. Unlike PathEndpoint origins, CircuitTermination has no `_path` back-reference
  2513. field, so saving and deleting such a path must not attempt to write it (see #22825).
  2514. """
  2515. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  2516. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  2517. PortMapping.objects.create(
  2518. device=self.device, front_port=frontport1, front_port_position=1,
  2519. rear_port=rearport1, rear_port_position=1,
  2520. )
  2521. circuittermination1 = CircuitTermination.objects.create(
  2522. circuit=self.circuit,
  2523. termination=self.site,
  2524. term_side='A'
  2525. )
  2526. cable1 = Cable(
  2527. a_terminations=[circuittermination1],
  2528. b_terminations=[rearport1]
  2529. )
  2530. cable1.save()
  2531. # Re-fetch so the in-memory instance reflects the cable set above (from_origin reads .cable).
  2532. circuittermination1.refresh_from_db()
  2533. # A path traced from the CircuitTermination origin must save without raising FieldDoesNotExist
  2534. # on the missing `_path` field.
  2535. cablepath = CablePath.from_origin([circuittermination1])
  2536. cablepath.save()
  2537. self.assertEqual(cablepath.origin_type.model_class(), CircuitTermination)
  2538. self.assertEqual(cablepath.origins, [circuittermination1])
  2539. # Deleting the path must likewise not attempt to clear a nonexistent `_path` field.
  2540. cablepath.delete()
  2541. self.assertIsNone(CablePath.objects.filter(pk=cablepath.pk).first())
  2542. def test_301_create_path_via_existing_cable(self):
  2543. """
  2544. [IF1] --C1-- [FP1] [RP1] --C2-- [RP2] [FP2] --C3-- [IF2]
  2545. """
  2546. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2547. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2548. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  2549. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  2550. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  2551. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  2552. PortMapping.objects.bulk_create([
  2553. PortMapping(
  2554. device=self.device,
  2555. front_port=frontport1,
  2556. front_port_position=1,
  2557. rear_port=rearport1,
  2558. rear_port_position=1,
  2559. ),
  2560. PortMapping(
  2561. device=self.device,
  2562. front_port=frontport2,
  2563. front_port_position=1,
  2564. rear_port=rearport2,
  2565. rear_port_position=1,
  2566. ),
  2567. ])
  2568. # Create cable 2
  2569. cable2 = Cable(
  2570. a_terminations=[rearport1],
  2571. b_terminations=[rearport2]
  2572. )
  2573. cable2.save()
  2574. self.assertEqual(CablePath.objects.count(), 0)
  2575. # Create cable1
  2576. cable1 = Cable(
  2577. a_terminations=[interface1],
  2578. b_terminations=[frontport1]
  2579. )
  2580. cable1.save()
  2581. self.assertPathExists(
  2582. (interface1, cable1, frontport1, rearport1, cable2, rearport2, frontport2),
  2583. is_complete=False
  2584. )
  2585. self.assertEqual(CablePath.objects.count(), 1)
  2586. # Create cable 3
  2587. cable3 = Cable(
  2588. a_terminations=[frontport2],
  2589. b_terminations=[interface2]
  2590. )
  2591. cable3.save()
  2592. self.assertPathExists(
  2593. (interface1, cable1, frontport1, rearport1, cable2, rearport2, frontport2, cable3, interface2),
  2594. is_complete=True,
  2595. is_active=True
  2596. )
  2597. self.assertPathExists(
  2598. (interface2, cable3, frontport2, rearport2, cable2, rearport1, frontport1, cable1, interface1),
  2599. is_complete=True,
  2600. is_active=True
  2601. )
  2602. self.assertEqual(CablePath.objects.count(), 2)
  2603. def test_302_update_path_on_cable_status_change(self):
  2604. """
  2605. [IF1] --C1-- [FP1] [RP1] --C2-- [IF2]
  2606. """
  2607. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2608. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2609. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  2610. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  2611. PortMapping.objects.bulk_create([
  2612. PortMapping(
  2613. device=self.device,
  2614. front_port=frontport1,
  2615. front_port_position=1,
  2616. rear_port=rearport1,
  2617. rear_port_position=1,
  2618. ),
  2619. ])
  2620. # Create cables 1 and 2
  2621. cable1 = Cable(
  2622. a_terminations=[interface1],
  2623. b_terminations=[frontport1]
  2624. )
  2625. cable1.save()
  2626. cable2 = Cable(
  2627. a_terminations=[rearport1],
  2628. b_terminations=[interface2]
  2629. )
  2630. cable2.save()
  2631. self.assertEqual(CablePath.objects.filter(is_active=True).count(), 2)
  2632. self.assertEqual(CablePath.objects.count(), 2)
  2633. # Change cable 2's status to "planned"
  2634. cable2 = Cable.objects.get(pk=cable2.pk) # Rebuild object to ditch A/B terminations set earlier
  2635. cable2.status = LinkStatusChoices.STATUS_PLANNED
  2636. cable2.save()
  2637. self.assertPathExists(
  2638. (interface1, cable1, frontport1, rearport1, cable2, interface2),
  2639. is_complete=True,
  2640. is_active=False
  2641. )
  2642. self.assertPathExists(
  2643. (interface2, cable2, rearport1, frontport1, cable1, interface1),
  2644. is_complete=True,
  2645. is_active=False
  2646. )
  2647. self.assertEqual(CablePath.objects.count(), 2)
  2648. # Change cable 2's status to "connected"
  2649. cable2 = Cable.objects.get(pk=cable2.pk)
  2650. cable2.status = LinkStatusChoices.STATUS_CONNECTED
  2651. cable2.save()
  2652. self.assertPathExists(
  2653. (interface1, cable1, frontport1, rearport1, cable2, interface2),
  2654. is_complete=True,
  2655. is_active=True
  2656. )
  2657. self.assertPathExists(
  2658. (interface2, cable2, rearport1, frontport1, cable1, interface1),
  2659. is_complete=True,
  2660. is_active=True
  2661. )
  2662. self.assertEqual(CablePath.objects.count(), 2)
  2663. def test_303_remove_termination_from_existing_cable(self):
  2664. """
  2665. [IF1] --C1-- [IF2]
  2666. [IF3]
  2667. """
  2668. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2669. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2670. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  2671. cable1 = Cable(
  2672. a_terminations=[interface1],
  2673. b_terminations=[interface2, interface3]
  2674. )
  2675. cable1.save()
  2676. self.assertPathExists(
  2677. (interface1, cable1, [interface2, interface3]),
  2678. is_complete=True,
  2679. is_active=True
  2680. )
  2681. self.assertPathExists(
  2682. ([interface2, interface3], cable1, interface1),
  2683. is_complete=True,
  2684. is_active=True
  2685. )
  2686. # Remove the termination to interface 3
  2687. cable1 = Cable.objects.first()
  2688. cable1.b_terminations = [interface2]
  2689. cable1.save()
  2690. self.assertPathExists(
  2691. (interface1, cable1, interface2),
  2692. is_complete=True,
  2693. is_active=True
  2694. )
  2695. self.assertPathExists(
  2696. (interface2, cable1, interface1),
  2697. is_complete=True,
  2698. is_active=True
  2699. )
  2700. # Verify _path is cleared on removed interface (#21127)
  2701. interface3.refresh_from_db()
  2702. self.assertPathIsNotSet(interface3)
  2703. self.assertEqual(CablePath.objects.count(), 2)
  2704. def test_304_replacing_a_termination_retires_superseded_paths(self):
  2705. """
  2706. [IF1] --C1-- [IF2] becomes [IF1] --C1-- [IF3], and back again
  2707. Each replacement must leave only the two paths the cable's current terminations trace.
  2708. """
  2709. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2710. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2711. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  2712. cable1 = Cable(a_terminations=[interface1], b_terminations=[interface2])
  2713. cable1.save()
  2714. self.assertEqual(CablePath.objects.count(), 2)
  2715. for peer, detached in ((interface3, interface2), (interface2, interface3)):
  2716. with self.subTest(peer=peer.name):
  2717. cable1 = Cable.objects.get(pk=cable1.pk)
  2718. cable1.b_terminations = [peer]
  2719. cable1.full_clean()
  2720. cable1.save()
  2721. self.assertCurrentPathExists((interface1, cable1, peer), is_complete=True, is_active=True)
  2722. self.assertCurrentPathExists((peer, cable1, interface1), is_complete=True, is_active=True)
  2723. self.assertEqual(CablePath.objects.count(), 2)
  2724. detached.refresh_from_db()
  2725. self.assertIsNone(detached.cable)
  2726. self.assertPathIsNotSet(detached)
  2727. def test_305_adding_a_termination_retires_superseded_paths(self):
  2728. """
  2729. [IF1] --C1-- [IF2] gains a second B-side termination [IF3]
  2730. Extending an end must retire the paths whose destinations the extension supersedes.
  2731. """
  2732. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2733. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2734. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  2735. cable1 = Cable(a_terminations=[interface1], b_terminations=[interface2])
  2736. cable1.save()
  2737. self.assertEqual(CablePath.objects.count(), 2)
  2738. cable1 = Cable.objects.get(pk=cable1.pk)
  2739. cable1.b_terminations = [interface2, interface3]
  2740. cable1.full_clean()
  2741. cable1.save()
  2742. self.assertCurrentPathExists(
  2743. (interface1, cable1, [interface2, interface3]), is_complete=True, is_active=True
  2744. )
  2745. path2 = self.assertPathExists(
  2746. ([interface2, interface3], cable1, interface1), is_complete=True, is_active=True
  2747. )
  2748. for interface in (interface2, interface3):
  2749. interface.refresh_from_db()
  2750. self.assertPathIsSet(interface, path2)
  2751. self.assertEqual(CablePath.objects.count(), 2)
  2752. def test_306_retracing_one_joint_origin_restores_the_whole_hop(self):
  2753. """
  2754. [IF1] --C1-- [IF2]
  2755. [IF3]
  2756. trace_paths retraces a cable end as a unit, so repairing one co-origin restores the joint hop.
  2757. """
  2758. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2759. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2760. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  2761. cable1 = Cable(a_terminations=[interface1], b_terminations=[interface2, interface3])
  2762. cable1.save()
  2763. self.assertEqual(CablePath.objects.count(), 2)
  2764. # trace_paths selects on a null _path
  2765. Interface.objects.filter(pk=interface2.pk).update(_path=None)
  2766. call_command('trace_paths', no_input=True, stdout=StringIO())
  2767. for interface in (interface1, interface2, interface3):
  2768. interface.refresh_from_db()
  2769. self.assertIsNotNone(interface._path_id, msg=f'{interface} left without a path')
  2770. self.assertPathExists(([interface2, interface3], cable1, interface1))
  2771. self.assertEqual(CablePath.objects.count(), 2)
  2772. def test_307_retracing_a_cable_end_retires_a_superseded_co_origin_path(self):
  2773. """
  2774. [IF1] --C1-- [IF2]
  2775. [IF3]
  2776. A path superseded at a co-origin of the retraced end is retired, not left beside its replacement.
  2777. """
  2778. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2779. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2780. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  2781. cable1 = Cable(a_terminations=[interface1], b_terminations=[interface2, interface3])
  2782. cable1.save()
  2783. self.assertEqual(CablePath.objects.count(), 2)
  2784. # Seed the stale row a pre-fix install would hold, then restore both origins to the shared path
  2785. interface3 = Interface.objects.get(pk=interface3.pk)
  2786. joint_path = interface3._path
  2787. superseded = CablePath.from_origin([interface3])
  2788. superseded.save()
  2789. joint_path.save()
  2790. # trace_paths selects on a null _path
  2791. Interface.objects.filter(pk=interface2.pk).update(_path=None)
  2792. call_command('trace_paths', no_input=True, stdout=StringIO())
  2793. self.assertFalse(
  2794. CablePath.objects.filter(pk=superseded.pk).exists(), msg='the superseded path survived the retrace'
  2795. )
  2796. self.assertPathExists(([interface2, interface3], cable1, interface1))
  2797. self.assertEqual(CablePath.objects.count(), 2)
  2798. def test_308_retracing_a_partial_origin_group_retires_its_co_origins_paths(self):
  2799. """
  2800. Retracing one origin of a shared path must also replace its co-origin's stale paths.
  2801. """
  2802. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2803. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2804. interface3 = Interface.objects.create(device=self.device, name='Interface 3')
  2805. cable = Cable(a_terminations=[interface1], b_terminations=[interface2, interface3])
  2806. cable.save()
  2807. interface3.refresh_from_db()
  2808. joint_path = interface3._path
  2809. superseded = CablePath.from_origin([interface3])
  2810. superseded.save()
  2811. joint_path.save()
  2812. interface2.refresh_from_db()
  2813. create_cablepaths([interface2])
  2814. self.assertFalse(CablePath.objects.filter(pk=superseded.pk).exists())
  2815. self.assertFalse(CablePath.objects.filter(pk=joint_path.pk).exists())
  2816. self.assertCurrentPathExists((interface2, cable, interface1), is_complete=True)
  2817. self.assertCurrentPathExists((interface3, cable, interface1), is_complete=True)
  2818. self.assertCurrentPathExists((interface1, cable, [interface2, interface3]), is_complete=True)
  2819. self.assertEqual(CablePath.objects.count(), 3)
  2820. def test_309_retracing_preserves_another_current_origin_group(self):
  2821. """
  2822. An origin group whose references the deletion does not clear is left intact, rows and all.
  2823. """
  2824. interfaces = [
  2825. Interface.objects.create(device=self.device, name=f'Interface {i}') for i in range(1, 5)
  2826. ]
  2827. interface1, interface2, interface3, interface4 = interfaces
  2828. cable = Cable(a_terminations=[interface1], b_terminations=interfaces[1:])
  2829. cable.save()
  2830. for interface in interfaces:
  2831. interface.refresh_from_db()
  2832. # Overlapping groups from earlier partial retraces, with interface3 and interface4 on the second
  2833. interface2._path.delete()
  2834. first = CablePath.from_origin([interface2, interface3])
  2835. first.save()
  2836. second = CablePath.from_origin([interface3, interface4])
  2837. second.save()
  2838. create_cablepaths([interface2])
  2839. self.assertFalse(CablePath.objects.filter(pk=first.pk).exists())
  2840. self.assertCurrentPathExists((interface2, cable, interface1), is_complete=True)
  2841. self.assertTrue(
  2842. CablePath.objects.filter(pk=second.pk).exists(), msg='the untouched origin group was replaced'
  2843. )
  2844. second.refresh_from_db()
  2845. self.assertEqual(second.path[0], [object_to_path_node(interface3), object_to_path_node(interface4)])
  2846. for interface in (interface3, interface4):
  2847. interface.refresh_from_db()
  2848. self.assertPathIsSet(interface, second)
  2849. self.assertEqual(CablePath.objects.count(), 3)
  2850. def test_313_recovery_follows_a_chain_of_cleared_references(self):
  2851. """
  2852. Recovering an origin can clear another group's references, whose origins are recovered in turn.
  2853. """
  2854. interfaces = [
  2855. Interface.objects.create(device=self.device, name=f'Interface {i}') for i in range(1, 5)
  2856. ]
  2857. interface1, interface2, interface3, interface4 = interfaces
  2858. cable = Cable(a_terminations=[interface1], b_terminations=interfaces[1:])
  2859. cable.save()
  2860. for interface in interfaces:
  2861. interface.refresh_from_db()
  2862. # interface3 references the first group, so losing it starts the chain
  2863. interface2._path.delete()
  2864. first = CablePath.from_origin([interface2, interface3])
  2865. first.save()
  2866. second = CablePath.from_origin([interface3, interface4])
  2867. second.save()
  2868. first.save()
  2869. create_cablepaths([interface2])
  2870. self.assertFalse(CablePath.objects.filter(pk__in=[first.pk, second.pk]).exists())
  2871. for interface in interfaces[1:]:
  2872. self.assertCurrentPathExists((interface, cable, interface1), is_complete=True)
  2873. self.assertEqual(CablePath.objects.count(), 4)
  2874. def test_310_recovery_preserves_the_requested_connector_groups(self):
  2875. """
  2876. A recovered group must not replace a connector group already rebuilt by this call.
  2877. """
  2878. interfaces = [
  2879. Interface.objects.create(device=self.device, name=f'Interface {i}') for i in range(1, 5)
  2880. ]
  2881. interface1, interface2, interface3, interface4 = interfaces
  2882. cable = Cable(a_terminations=[interface1], b_terminations=interfaces[1:])
  2883. cable.save()
  2884. for interface in interfaces:
  2885. interface.refresh_from_db()
  2886. CablePath.from_origin([interface2, interface3]).save()
  2887. # Exercise helper grouping without changing the persisted termination topology.
  2888. interface2.cable_connector = 1
  2889. interface3.cable_connector = 2
  2890. interface4.cable_connector = 2
  2891. create_cablepaths([interface2, interface3, interface4])
  2892. self.assertCurrentPathExists((interface2, cable, interface1), is_complete=True)
  2893. shared_path = self.assertPathExists(([interface3, interface4], cable, interface1), is_complete=True)
  2894. for interface in (interface3, interface4):
  2895. interface.refresh_from_db()
  2896. self.assertPathIsSet(interface, shared_path)
  2897. self.assertEqual(CablePath.objects.count(), 3)
  2898. def test_311_recovery_separates_origins_on_different_links(self):
  2899. """
  2900. A stale origin hop holding origins since moved apart is recovered as one group per current link.
  2901. """
  2902. interfaces = [
  2903. Interface.objects.create(device=self.device, name=f'Interface {i}') for i in range(1, 7)
  2904. ]
  2905. interface1, interface2, interface3, interface4, interface5, interface6 = interfaces
  2906. cable1 = Cable(
  2907. a_terminations=[interface1],
  2908. b_terminations=[interface2, interface3, interface4, interface5],
  2909. )
  2910. cable1.save()
  2911. # The hop as stored while all four shared cable1
  2912. interface2.refresh_from_db()
  2913. stale_nodes = interface2._path.path
  2914. # Move one origin through ordinary saves, so only the CablePath below is stale
  2915. cable1.b_terminations = [interface2, interface3, interface4]
  2916. cable1.save()
  2917. interface5.refresh_from_db()
  2918. cable2 = Cable(a_terminations=[interface6], b_terminations=[interface5])
  2919. cable2.save()
  2920. interface2.refresh_from_db()
  2921. interface5.refresh_from_db()
  2922. current_cable1 = interface2._path
  2923. current_cable2 = interface5._path
  2924. # Leave the obsolete row as their only originating path, so recovery gets the whole mixed hop
  2925. current_cable1.delete()
  2926. current_cable2.delete()
  2927. superseded = CablePath(path=stale_nodes, is_complete=True, is_active=True)
  2928. superseded.save()
  2929. create_cablepaths([Interface.objects.get(pk=interface2.pk)])
  2930. self.assertFalse(CablePath.objects.filter(pk=superseded.pk).exists())
  2931. self.assertCurrentPathExists((interface2, cable1, interface1), is_complete=True)
  2932. # The origins still sharing cable1 stay one group, and the moved one is recovered on its own cable
  2933. shared = self.assertPathExists(([interface3, interface4], cable1, interface1), is_complete=True)
  2934. for interface in (interface3, interface4):
  2935. interface.refresh_from_db()
  2936. self.assertPathIsSet(interface, shared)
  2937. self.assertCurrentPathExists((interface5, cable2, interface6), is_complete=True)
  2938. self.assertEqual(CablePath.objects.count(), 5)
  2939. def test_312_retracing_repairs_an_endpoint_whose_cable_end_drifted(self):
  2940. """
  2941. An endpoint whose denormalized cable_end no longer matches its CableTermination is still retraced.
  2942. """
  2943. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2944. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2945. cable1 = Cable(a_terminations=[interface1], b_terminations=[interface2])
  2946. cable1.save()
  2947. # The termination row still says B, which is the drift this command exists to repair
  2948. Interface.objects.filter(pk=interface2.pk).update(
  2949. _path=None, cable_end=CableEndChoices.SIDE_A
  2950. )
  2951. call_command('trace_paths', no_input=True, stdout=StringIO())
  2952. self.assertCurrentPathExists((interface2, cable1, interface1), is_complete=True)
  2953. self.assertEqual(CablePath.objects.count(), 2)
  2954. def test_401_exclude_midspan_devices(self):
  2955. """
  2956. [IF1] --C1-- [FP1][Test Device][RP1] --C2-- [RP2][Test Device][FP2] --C3-- [IF2]
  2957. [FP3][Test mid-span Device][RP3] --C4-- [RP4][Test mid-span Device][FP4] /
  2958. """
  2959. device = Device.objects.create(
  2960. site=self.site,
  2961. device_type=self.device.device_type,
  2962. role=self.device.role,
  2963. name='Test mid-span Device'
  2964. )
  2965. interface1 = Interface.objects.create(device=self.device, name='Interface 1')
  2966. interface2 = Interface.objects.create(device=self.device, name='Interface 2')
  2967. rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1')
  2968. rearport2 = RearPort.objects.create(device=self.device, name='Rear Port 2')
  2969. rearport3 = RearPort.objects.create(device=device, name='Rear Port 3')
  2970. rearport4 = RearPort.objects.create(device=device, name='Rear Port 4')
  2971. frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1')
  2972. frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2')
  2973. frontport3 = FrontPort.objects.create(device=self.device, name='Front Port 3')
  2974. frontport4 = FrontPort.objects.create(device=self.device, name='Front Port 4')
  2975. PortMapping.objects.bulk_create([
  2976. PortMapping(
  2977. device=self.device,
  2978. front_port=frontport1,
  2979. front_port_position=1,
  2980. rear_port=rearport1,
  2981. rear_port_position=1,
  2982. ),
  2983. PortMapping(
  2984. device=self.device,
  2985. front_port=frontport2,
  2986. front_port_position=1,
  2987. rear_port=rearport2,
  2988. rear_port_position=1,
  2989. ),
  2990. PortMapping(
  2991. device=self.device,
  2992. front_port=frontport3,
  2993. front_port_position=1,
  2994. rear_port=rearport3,
  2995. rear_port_position=1,
  2996. ),
  2997. PortMapping(
  2998. device=self.device,
  2999. front_port=frontport4,
  3000. front_port_position=1,
  3001. rear_port=rearport4,
  3002. rear_port_position=1,
  3003. ),
  3004. ])
  3005. cable2 = Cable(
  3006. a_terminations=[rearport1],
  3007. b_terminations=[rearport2],
  3008. label='C2'
  3009. )
  3010. cable2.save()
  3011. cable4 = Cable(
  3012. a_terminations=[rearport3],
  3013. b_terminations=[rearport4],
  3014. label='C4'
  3015. )
  3016. cable4.save()
  3017. self.assertEqual(CablePath.objects.count(), 0)
  3018. # Create cable1
  3019. cable1 = Cable(
  3020. a_terminations=[interface1],
  3021. b_terminations=[frontport1, frontport3],
  3022. label='C1'
  3023. )
  3024. with self.assertRaises(AbortRequest):
  3025. cable1.save()
  3026. self.assertPathDoesNotExist(
  3027. (
  3028. interface1, cable1, (frontport1, frontport3), (rearport1, rearport3), (cable2, cable4),
  3029. (rearport2, rearport4), (frontport2, frontport4)
  3030. ),
  3031. is_complete=False
  3032. )
  3033. self.assertEqual(CablePath.objects.count(), 0)
  3034. # Create cable 3
  3035. cable3 = Cable(
  3036. a_terminations=[frontport2, frontport4],
  3037. b_terminations=[interface2],
  3038. label='C3'
  3039. )
  3040. with self.assertRaises(AbortRequest):
  3041. cable3.save()
  3042. self.assertPathDoesNotExist(
  3043. (
  3044. interface2, cable3, (frontport2, frontport4), (rearport2, rearport4), (cable2, cable4),
  3045. (rearport1, rearport3), (frontport1, frontport2), cable1, interface1
  3046. ),
  3047. is_complete=True,
  3048. is_active=True
  3049. )
  3050. self.assertPathDoesNotExist(
  3051. (
  3052. interface1, cable1, (frontport1, frontport3), (rearport1, rearport3), (cable2, cable4),
  3053. (rearport2, rearport4), (frontport2, frontport4), cable3, interface2
  3054. ),
  3055. is_complete=True,
  3056. is_active=True
  3057. )
  3058. self.assertEqual(CablePath.objects.count(), 0)
  3059. def test_402_exclude_circuit_loopback(self):
  3060. interface = Interface.objects.create(device=self.device, name='Interface 1')
  3061. circuittermination1 = CircuitTermination.objects.create(
  3062. circuit=self.circuit,
  3063. termination=self.site,
  3064. term_side='A'
  3065. )
  3066. circuittermination2 = CircuitTermination.objects.create(
  3067. circuit=self.circuit,
  3068. termination=self.site,
  3069. term_side='Z'
  3070. )
  3071. # Create cables
  3072. cable = Cable(
  3073. a_terminations=[interface],
  3074. b_terminations=[circuittermination1, circuittermination2]
  3075. )
  3076. cable.save()
  3077. path = self.assertPathExists(
  3078. (interface, cable, (circuittermination1, circuittermination2)),
  3079. is_active=True,
  3080. is_complete=False,
  3081. is_split=True
  3082. )
  3083. self.assertEqual(CablePath.objects.count(), 1)
  3084. interface.refresh_from_db()
  3085. self.assertPathIsSet(interface, path)