synapse 2.169.0__py311-none-any.whl → 2.170.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (39) hide show
  1. synapse/cortex.py +88 -2
  2. synapse/datamodel.py +5 -0
  3. synapse/lib/ast.py +70 -12
  4. synapse/lib/cell.py +77 -7
  5. synapse/lib/layer.py +75 -6
  6. synapse/lib/node.py +7 -0
  7. synapse/lib/snap.py +22 -4
  8. synapse/lib/storm.py +1 -1
  9. synapse/lib/stormlib/cortex.py +1 -1
  10. synapse/lib/stormlib/model.py +339 -40
  11. synapse/lib/stormtypes.py +58 -1
  12. synapse/lib/types.py +35 -0
  13. synapse/lib/version.py +2 -2
  14. synapse/lib/view.py +87 -14
  15. synapse/models/files.py +40 -0
  16. synapse/models/inet.py +8 -4
  17. synapse/models/infotech.py +355 -17
  18. synapse/tests/files/cpedata.json +525034 -0
  19. synapse/tests/test_cortex.py +99 -0
  20. synapse/tests/test_lib_ast.py +66 -0
  21. synapse/tests/test_lib_cell.py +112 -0
  22. synapse/tests/test_lib_layer.py +52 -1
  23. synapse/tests/test_lib_scrape.py +72 -71
  24. synapse/tests/test_lib_snap.py +16 -1
  25. synapse/tests/test_lib_storm.py +118 -0
  26. synapse/tests/test_lib_stormlib_cortex.py +15 -0
  27. synapse/tests/test_lib_stormlib_model.py +427 -0
  28. synapse/tests/test_lib_stormtypes.py +135 -14
  29. synapse/tests/test_lib_types.py +20 -0
  30. synapse/tests/test_lib_view.py +77 -0
  31. synapse/tests/test_model_files.py +51 -0
  32. synapse/tests/test_model_inet.py +63 -1
  33. synapse/tests/test_model_infotech.py +187 -26
  34. synapse/tests/utils.py +12 -0
  35. {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/METADATA +1 -1
  36. {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/RECORD +39 -38
  37. {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/LICENSE +0 -0
  38. {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/WHEEL +0 -0
  39. {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/top_level.txt +0 -0
@@ -3568,6 +3568,114 @@ class StormTypesTest(s_test.SynTest):
3568
3568
  self.eq(counts.get('test:int'), 2)
3569
3569
  self.eq(counts.get('test:guid'), 1)
3570
3570
 
3571
+ async def test_storm_lib_layer_sodebyform(self):
3572
+ async with self.getTestCore() as core:
3573
+
3574
+ await core.nodes('$lib.model.ext.addTagProp(score, (int, ({})), ({}))')
3575
+
3576
+ view_prop = await core.callStorm('return($lib.view.get().fork().iden)')
3577
+ view_tags = await core.callStorm('return($lib.view.get().fork().iden)')
3578
+ view_tagp = await core.callStorm('return($lib.view.get().fork().iden)')
3579
+ view_n1eg = await core.callStorm('return($lib.view.get().fork().iden)')
3580
+ view_n2eg = await core.callStorm('return($lib.view.get().fork().iden)')
3581
+ view_data = await core.callStorm('return($lib.view.get().fork().iden)')
3582
+ view_noop = await core.callStorm('return($lib.view.get().fork().iden)')
3583
+
3584
+ self.len(1, await core.nodes('[ test:str=foo +#base ]'))
3585
+ self.len(1, await core.nodes('test:str=foo [ :hehe=haha ]', opts={'view': view_prop}))
3586
+ self.len(1, await core.nodes('test:str=foo [ +#bar ]', opts={'view': view_tags}))
3587
+ self.len(1, await core.nodes('test:str=foo [ +#base:score=10 ]', opts={'view': view_tagp}))
3588
+ self.len(1, await core.nodes('test:str=foo [ +(bam)> {[ test:int=2 ]} ]', opts={'view': view_n1eg}))
3589
+ self.len(1, await core.nodes('test:str=foo [ <(bam)+ {[ test:int=1 ]} ]', opts={'view': view_n2eg}))
3590
+ self.len(1, await core.nodes('test:str=foo $node.data.set(hehe, haha)', opts={'view': view_data}))
3591
+
3592
+ scmd = '''
3593
+ $sodes = ([])
3594
+ for $sode in $lib.layer.get().getStorNodesByForm($form) {
3595
+ $sodes.append($sode)
3596
+ }
3597
+ return($sodes)
3598
+ '''
3599
+ opts = {'vars': {'form': 'test:str'}}
3600
+
3601
+ self.len(1, await core.callStorm(scmd, opts=opts))
3602
+ self.len(1, await core.callStorm(scmd, opts={**opts, 'view': view_prop}))
3603
+ self.len(1, await core.callStorm(scmd, opts={**opts, 'view': view_tags}))
3604
+ self.len(1, await core.callStorm(scmd, opts={**opts, 'view': view_tagp}))
3605
+ self.len(1, await core.callStorm(scmd, opts={**opts, 'view': view_n1eg}))
3606
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_n2eg})) # n2-only sode not added
3607
+ self.len(1, await core.callStorm(scmd, opts={**opts, 'view': view_data}))
3608
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_noop}))
3609
+
3610
+ self.len(1, await core.nodes('test:str=foo [ -:hehe ]', opts={'view': view_prop}))
3611
+ self.len(1, await core.nodes('test:str=foo [ -#bar ]', opts={'view': view_tags}))
3612
+ self.len(1, await core.nodes('test:str=foo [ -#base:score ]', opts={'view': view_tagp}))
3613
+ self.len(1, await core.nodes('test:str=foo [ -(bam)> {[ test:int=2 ]} ]', opts={'view': view_n1eg}))
3614
+ self.len(1, await core.nodes('test:str=foo [ <(bam)- {[ test:int=1 ]} ]', opts={'view': view_n2eg}))
3615
+ self.len(1, await core.nodes('test:str=foo $node.data.pop(hehe)', opts={'view': view_data}))
3616
+
3617
+ self.len(1, await core.callStorm(scmd, opts=opts))
3618
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_prop}))
3619
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_tags}))
3620
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_tagp}))
3621
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_n1eg}))
3622
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_n2eg}))
3623
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_data}))
3624
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_noop}))
3625
+
3626
+ self.len(1, await core.nodes('''
3627
+ test:str=foo [
3628
+ :hehe=lol
3629
+ +#baz
3630
+ +#base:score=11
3631
+ +(bar)> {[ test:int=2 ]}
3632
+ <(bar)+ {[ test:int=1 ]}
3633
+ ]
3634
+ $node.data.set(haha, lol)
3635
+ '''))
3636
+ self.len(1, await core.nodes('test:str=foo [ :hehe=lol ]', opts={'view': view_prop}))
3637
+ self.len(1, await core.nodes('test:str=foo [ +#baz ]', opts={'view': view_tags}))
3638
+ self.len(1, await core.nodes('test:str=foo [ +#base:score=11 ]', opts={'view': view_tagp}))
3639
+ self.len(1, await core.nodes('test:str=foo [ +(bar)> {[ test:int=2 ]} ]', opts={'view': view_n1eg}))
3640
+ self.len(1, await core.nodes('test:str=foo [ <(bar)+ {[ test:int=1 ]} ]', opts={'view': view_n2eg}))
3641
+ self.len(1, await core.nodes('test:str=foo $node.data.set(haha, lol)', opts={'view': view_data}))
3642
+
3643
+ self.len(1, await core.callStorm(scmd, opts=opts))
3644
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_prop}))
3645
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_tags}))
3646
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_tagp}))
3647
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_n1eg}))
3648
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_n2eg}))
3649
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_data}))
3650
+ self.len(0, await core.callStorm(scmd, opts={**opts, 'view': view_noop}))
3651
+
3652
+ self.len(1, await core.nodes('''
3653
+ test:str=foo [
3654
+ -:hehe
3655
+ -#baz
3656
+ -#base:score -#base
3657
+ -(bar)> { test:int=2 }
3658
+ <(bar)- { test:int=1 }
3659
+ ]
3660
+ $node.data.pop(haha)
3661
+ '''))
3662
+ self.len(1, await core.callStorm(scmd, opts=opts))
3663
+
3664
+ await core.nodes('test:str=foo delnode')
3665
+ self.len(0, await core.callStorm(scmd, opts=opts))
3666
+
3667
+ # sad
3668
+
3669
+ await self.asyncraises(s_exc.NoSuchForm, core.callStorm(scmd, opts={'vars': {'form': 'newp:newp'}}))
3670
+
3671
+ lowuser = await core.auth.addUser('low')
3672
+ lowopts = opts | {'user': lowuser.iden, 'view': view_prop}
3673
+
3674
+ await self.asyncraises(s_exc.AuthDeny, core.callStorm(scmd, opts=lowopts))
3675
+
3676
+ await lowuser.addRule((True, ('view', 'read')), gateiden=view_prop)
3677
+ await core.callStorm(scmd, opts=lowopts)
3678
+
3571
3679
  async def test_storm_lib_layer_upstream(self):
3572
3680
  async with self.getTestCore() as core:
3573
3681
  async with self.getTestCore() as core2:
@@ -6596,11 +6704,10 @@ words\tword\twrd'''
6596
6704
  self.nn(await core.callStorm('return($lib.view.get().setMergeRequest())', opts=opts))
6597
6705
  self.eq([fork.iden], await core.callStorm(merging))
6598
6706
 
6599
- # confirm that you may not re-parent to a view with a merge request
6707
+ # confirm that you may re-parent to a view with a merge request
6600
6708
  layr = await core.addLayer()
6601
6709
  vdef = await core.addView({'layers': (layr['iden'],)})
6602
- with self.raises(s_exc.BadState):
6603
- await core.getView(vdef['iden']).setViewInfo('parent', fork.iden)
6710
+ await core.getView(vdef['iden']).setViewInfo('parent', fork.iden)
6604
6711
 
6605
6712
  opts = {'view': fork.iden, 'user': visi.iden}
6606
6713
  self.nn(await core.callStorm('return($lib.view.get().setMergeVote(approved=(false)))', opts=opts))
@@ -6650,28 +6757,42 @@ words\tword\twrd'''
6650
6757
 
6651
6758
  self.eq([], await core.callStorm(merging))
6652
6759
 
6653
- # test coverage for bad state for merge request
6760
+ # merge a view with a fork
6654
6761
  fork00 = await core.getView().fork()
6655
- fork01 = await core.getView(fork00['iden']).fork()
6762
+ midfork = core.getView(fork00['iden'])
6656
6763
 
6657
- opts = {'view': fork00['iden']}
6658
- with self.raises(s_exc.BadState):
6659
- await core.callStorm('return($lib.view.get().setMergeRequest())', opts=opts)
6764
+ fork01 = await midfork.fork()
6765
+ self.true(midfork.hasKids())
6766
+
6767
+ opts = {'view': midfork.iden}
6768
+ await core.callStorm('return($lib.view.get().setMergeRequest())', opts=opts)
6769
+
6770
+ self.eq([midfork.iden], await core.callStorm(merging))
6771
+
6772
+ opts = {'view': midfork.iden, 'user': visi.iden}
6773
+ await core.callStorm('return($lib.view.get().setMergeVote())', opts=opts)
6774
+
6775
+ self.true(await midfork.waitfini(timeout=12))
6660
6776
 
6661
6777
  self.eq([], await core.callStorm(merging))
6662
6778
 
6663
- await core.delView(fork01['iden'])
6779
+ leaffork = core.getView(fork01['iden'])
6780
+ self.false(leaffork.hasKids())
6781
+
6782
+ self.len(2, leaffork.layers)
6783
+ self.eq(leaffork.parent, core.getView())
6784
+
6785
+ # test coverage for bad state for merge request
6786
+ opts = {'view': fork01['iden']}
6664
6787
  await core.callStorm('return($lib.view.get().setMergeRequest())', opts=opts)
6665
- self.eq([fork00['iden']], await core.callStorm(merging))
6788
+ self.eq([fork01['iden']], await core.callStorm(merging))
6666
6789
 
6667
6790
  core.getView().layers[0].readonly = True
6668
6791
  with self.raises(s_exc.BadState):
6669
6792
  await core.callStorm('return($lib.view.get().setMergeRequest())', opts=opts)
6670
6793
 
6671
6794
  core.getView().layers[0].readonly = False
6672
-
6673
- with self.raises(s_exc.BadState):
6674
- await core.callStorm('return($lib.view.get().fork())', opts=opts)
6795
+ await core.callStorm('return($lib.view.get().fork())', opts=opts)
6675
6796
 
6676
6797
  # setup a new merge and make a mirror...
6677
6798
  forkdef = await core.getView().fork()
@@ -6681,7 +6802,7 @@ words\tword\twrd'''
6681
6802
  await core.stormlist('[ inet:ipv4=5.5.5.5 ]', opts=opts)
6682
6803
  await core.callStorm('return($lib.view.get().setMergeRequest())', opts=opts)
6683
6804
 
6684
- self.eq(set([fork.iden, fork00['iden']]), set(await core.callStorm(merging)))
6805
+ self.eq(set([fork.iden, fork01['iden']]), set(await core.callStorm(merging)))
6685
6806
 
6686
6807
  # hamstring the runViewMerge method on the new view
6687
6808
  async def fake():
@@ -939,6 +939,26 @@ class TypesTest(s_t_utils.SynTest):
939
939
  self.raises(s_exc.NoSuchForm, t.repr, ('test:newp', 'newp'))
940
940
  self.raises(s_exc.BadTypeValu, t.norm, ('newp',))
941
941
 
942
+ ndef = core.model.type('test:ndef:formfilter1')
943
+ ndef.norm(('inet:ipv4', '1.2.3.4'))
944
+ ndef.norm(('inet:ipv6', '::1'))
945
+
946
+ with self.raises(s_exc.BadTypeValu):
947
+ ndef.norm(('inet:fqdn', 'newp.com'))
948
+
949
+ ndef = core.model.type('test:ndef:formfilter2')
950
+ ndef.norm(('ou:orgtype', 'foo'))
951
+
952
+ with self.raises(s_exc.BadTypeValu):
953
+ ndef.norm(('inet:fqdn', 'newp.com'))
954
+
955
+ ndef = core.model.type('test:ndef:formfilter3')
956
+ ndef.norm(('inet:ipv4', '1.2.3.4'))
957
+ ndef.norm(('file:mime:msdoc', s_common.guid()))
958
+
959
+ with self.raises(s_exc.BadTypeValu):
960
+ ndef.norm(('inet:fqdn', 'newp.com'))
961
+
942
962
  async def test_nodeprop(self):
943
963
  async with self.getTestCore() as core:
944
964
  t = core.model.type('nodeprop')
@@ -828,3 +828,80 @@ class ViewTest(s_t_utils.SynTest):
828
828
 
829
829
  with self.raises(s_exc.AuthDeny) as cm:
830
830
  await core.nodes('$lib.view.get().merge()', opts=viewopts)
831
+
832
+ async def test_view_insert_parent_fork(self):
833
+
834
+ async with self.getTestCore() as core:
835
+
836
+ role = await core.auth.addRole('ninjas')
837
+ visi = await core.auth.addUser('visi')
838
+ asvisi = {'user': visi.iden}
839
+
840
+ view00 = core.getView()
841
+ view02 = core.getView((await view00.fork())['iden'])
842
+ view03 = core.getView((await view02.fork())['iden'])
843
+
844
+ self.eq(view02.parent, view00)
845
+
846
+ self.len(2, view02.layers)
847
+ self.len(3, view03.layers)
848
+
849
+ await view00.nodes('[ inet:fqdn=vertex.link ]')
850
+ await view02.nodes('inet:fqdn=vertex.link [ +#foo ]')
851
+
852
+ await view02.nodes('auth.user.addrule visi node --gate $lib.view.get().iden')
853
+ await view02.nodes('auth.user.mod visi --admin $lib.true --gate $lib.view.get().iden')
854
+ userrules = visi.getRules(gateiden=view02.iden)
855
+
856
+ await view02.nodes('auth.role.addrule ninjas node.add --gate $lib.view.get().iden')
857
+ rolerules = role.getRules(gateiden=view02.iden)
858
+
859
+ msgs = await core.stormlist('auth.user.addrule visi node --gate $lib.view.get().layers.0.iden')
860
+ self.stormHasNoWarnErr(msgs)
861
+
862
+ opts = {'vars': {'role': role.iden}}
863
+ quorum = await core.callStorm('return($lib.view.get().set(quorum, ({"count": 1, "roles": [$role]})))', opts=opts)
864
+
865
+ forkopts = {'view': view02.iden}
866
+ await core.callStorm('return($lib.view.get().setMergeRequest(comment=woot))', opts=forkopts)
867
+
868
+ merging = 'return($lib.view.get().getMergingViews()) '
869
+ self.eq([view02.iden], await core.callStorm(merging))
870
+
871
+ q = 'return($lib.view.get().insertParentFork(name=staging).iden)'
872
+ newiden = await core.callStorm(q, opts=forkopts)
873
+
874
+ self.eq([], await core.callStorm(merging))
875
+
876
+ view01 = core.getView(newiden)
877
+
878
+ self.ne(view02.parent, view00)
879
+ self.eq(view03.parent, view02)
880
+ self.eq(view02.parent, view01)
881
+ self.eq(view01.parent, view00)
882
+
883
+ self.len(2, view01.layers)
884
+ self.len(3, view02.layers)
885
+ self.len(4, view03.layers)
886
+ self.isin(view01.layers[0], view02.layers)
887
+ self.isin(view01.layers[0], view03.layers)
888
+
889
+ self.eq(userrules, visi.getRules(gateiden=view01.iden))
890
+ self.eq(rolerules, role.getRules(gateiden=view01.iden))
891
+
892
+ nodes = await view01.nodes('inet:fqdn=vertex.link')
893
+ self.none(nodes[0].getTag('foo'))
894
+
895
+ await core.nodes('merge --diff --apply', opts=forkopts)
896
+
897
+ nodes = await core.nodes('inet:fqdn=vertex.link')
898
+ self.none(nodes[0].getTag('foo'))
899
+
900
+ nodes = await view01.nodes('inet:fqdn=vertex.link')
901
+ self.nn(nodes[0].getTag('foo'))
902
+
903
+ with self.raises(s_exc.BadState):
904
+ await view00.insertParentFork(visi.iden)
905
+
906
+ with self.raises(s_exc.BadState):
907
+ await core.callStorm('return($lib.view.get().insertParentFork().iden)')
@@ -576,3 +576,54 @@ class FileTest(s_t_utils.SynTest):
576
576
  self.len(1, await core.nodes('file:archive:entry :user -> inet:user'))
577
577
  self.len(1, await core.nodes('file:archive:entry :file -> file:bytes'))
578
578
  self.len(1, await core.nodes('file:archive:entry :parent -> file:bytes'))
579
+
580
+ async def test_model_file_lnk(self):
581
+
582
+ async with self.getTestCore() as core:
583
+ nodes = await core.nodes(r'''[
584
+ file:mime:lnk=*
585
+ :entry:primary="c:\\some\\stuff\\prog~2\\cmd.exe"
586
+ :entry:secondary="c:\\some\\stuff\program files\\cmd.exe"
587
+ :entry:extended="c:\\some\\actual\\stuff\\I\\swear\\cmd.exe"
588
+ :entry:localized="c:\\some\\actual\\stuff\\I\\swear\\cmd.exe"
589
+ :entry:icon="%windir%\\system32\\notepad.exe"
590
+
591
+ :environment:path="%windir%\\system32\\cmd.exe"
592
+ :environment:icon="%some%%envvar%"
593
+ :working="%HOMEDRIVE%%HOMEPATH%"
594
+ :relative="..\\..\\..\\some\\foo.bar.txt"
595
+ :arguments="/q /c copy %systemroot%\\system32\\msh*.exe"
596
+ :desc="I've been here the whole time."
597
+
598
+ :flags=0x40df
599
+ :target:attrs=0x20
600
+ :target:size=12345
601
+ :target:created="2023/01/25 18:57:45.284"
602
+ :target:accessed="2023/01/25 18:57:45.284"
603
+ :target:written="2023/01/25 18:57:45.284"
604
+ ]''')
605
+ self.len(1, nodes)
606
+ node = nodes[0]
607
+
608
+ self.eq(node.get('entry:primary'), 'c:/some/stuff/prog~2/cmd.exe')
609
+ self.eq(node.get('entry:secondary'), 'c:/some/stuff/program files/cmd.exe')
610
+ self.eq(node.get('entry:extended'), 'c:/some/actual/stuff/i/swear/cmd.exe')
611
+ self.eq(node.get('entry:localized'), 'c:/some/actual/stuff/i/swear/cmd.exe')
612
+
613
+ self.eq(node.get('entry:icon'), '%windir%/system32/notepad.exe')
614
+ self.eq(node.get('environment:path'), '%windir%/system32/cmd.exe')
615
+ self.eq(node.get('environment:icon'), '%some%%envvar%')
616
+
617
+ self.eq(node.get('working'), '%homedrive%%homepath%')
618
+ self.eq(node.get('relative'), '..\\..\\..\\some\\foo.bar.txt')
619
+ self.eq(node.get('arguments'), '/q /c copy %systemroot%\\system32\\msh*.exe')
620
+ self.eq(node.get('desc'), "I've been here the whole time.")
621
+
622
+ self.eq(node.get('flags'), 0x40df)
623
+ self.eq(node.get('target:attrs'), 0x20)
624
+ self.eq(node.get('target:size'), 12345)
625
+
626
+ time = 1674673065284
627
+ self.eq(node.get('target:created'), time)
628
+ self.eq(node.get('target:accessed'), time)
629
+ self.eq(node.get('target:written'), time)
@@ -4,7 +4,6 @@ import logging
4
4
  import synapse.exc as s_exc
5
5
  import synapse.common as s_common
6
6
  import synapse.tests.utils as s_t_utils
7
- from synapse.tests.utils import alist
8
7
 
9
8
  logger = logging.getLogger(__name__)
10
9
 
@@ -166,6 +165,7 @@ class InetModelTest(s_t_utils.SynTest):
166
165
  # IPv6
167
166
  self.eq(t.norm('icmp://::1'), ('icmp://::1', {'subs': {'ipv6': '::1', 'proto': 'icmp'}}))
168
167
  self.eq(t.norm('tcp://[::1]:2'), ('tcp://[::1]:2', {'subs': {'ipv6': '::1', 'port': 2, 'proto': 'tcp'}}))
168
+ self.eq(t.norm('tcp://[::1]'), ('tcp://[::1]', {'subs': {'ipv6': '::1', 'proto': 'tcp'}}))
169
169
  self.eq(t.norm('tcp://[::fFfF:0102:0304]:2'),
170
170
  ('tcp://[::ffff:1.2.3.4]:2', {'subs': {'ipv6': '::ffff:1.2.3.4',
171
171
  'ipv4': 0x01020304,
@@ -1471,6 +1471,68 @@ class InetModelTest(s_t_utils.SynTest):
1471
1471
  self.none(nodes[0].get('ipv4'))
1472
1472
  self.none(nodes[0].get('fqdn'))
1473
1473
 
1474
+ q = '''
1475
+ [
1476
+ inet:url="http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html"
1477
+ inet:url="http://[1080:0:0:0:8:800:200C:417A]/index.html?foo=bar"
1478
+ inet:url="http://[3ffe:2a00:100:7031::1]"
1479
+ inet:url="http://[1080::8:800:200C:417A]/foo"
1480
+ inet:url="http://[::192.9.5.5]/ipng"
1481
+ inet:url="http://[::FFFF:129.144.52.38]:80/index.html"
1482
+ inet:url="https://[2010:836B:4179::836B:4179]"
1483
+ ]
1484
+ '''
1485
+ nodes = await core.nodes(q)
1486
+ self.len(7, nodes)
1487
+ self.eq(nodes[0].get('base'), 'http://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:80/index.html')
1488
+ self.eq(nodes[0].get('proto'), 'http')
1489
+ self.eq(nodes[0].get('path'), '/index.html')
1490
+ self.eq(nodes[0].get('params'), '')
1491
+ self.eq(nodes[0].get('ipv6'), 'fedc:ba98:7654:3210:fedc:ba98:7654:3210')
1492
+ self.eq(nodes[0].get('port'), 80)
1493
+
1494
+ self.eq(nodes[1].get('base'), 'http://[1080::8:800:200c:417a]/index.html')
1495
+ self.eq(nodes[1].get('proto'), 'http')
1496
+ self.eq(nodes[1].get('path'), '/index.html')
1497
+ self.eq(nodes[1].get('params'), '?foo=bar')
1498
+ self.eq(nodes[1].get('ipv6'), '1080::8:800:200c:417a')
1499
+ self.eq(nodes[1].get('port'), 80)
1500
+
1501
+ self.eq(nodes[2].get('base'), 'http://[3ffe:2a00:100:7031::1]')
1502
+ self.eq(nodes[2].get('proto'), 'http')
1503
+ self.eq(nodes[2].get('path'), '')
1504
+ self.eq(nodes[2].get('params'), '')
1505
+ self.eq(nodes[2].get('ipv6'), '3ffe:2a00:100:7031::1')
1506
+ self.eq(nodes[2].get('port'), 80)
1507
+
1508
+ self.eq(nodes[3].get('base'), 'http://[1080::8:800:200c:417a]/foo')
1509
+ self.eq(nodes[3].get('proto'), 'http')
1510
+ self.eq(nodes[3].get('path'), '/foo')
1511
+ self.eq(nodes[3].get('params'), '')
1512
+ self.eq(nodes[3].get('ipv6'), '1080::8:800:200c:417a')
1513
+ self.eq(nodes[3].get('port'), 80)
1514
+
1515
+ self.eq(nodes[4].get('base'), 'http://[::c009:505]/ipng')
1516
+ self.eq(nodes[4].get('proto'), 'http')
1517
+ self.eq(nodes[4].get('path'), '/ipng')
1518
+ self.eq(nodes[4].get('params'), '')
1519
+ self.eq(nodes[4].get('ipv6'), '::c009:505')
1520
+ self.eq(nodes[4].get('port'), 80)
1521
+
1522
+ self.eq(nodes[5].get('base'), 'http://[::ffff:129.144.52.38]:80/index.html')
1523
+ self.eq(nodes[5].get('proto'), 'http')
1524
+ self.eq(nodes[5].get('path'), '/index.html')
1525
+ self.eq(nodes[5].get('params'), '')
1526
+ self.eq(nodes[5].get('ipv6'), '::ffff:129.144.52.38')
1527
+ self.eq(nodes[5].get('port'), 80)
1528
+
1529
+ self.eq(nodes[6].get('base'), 'https://[2010:836b:4179::836b:4179]')
1530
+ self.eq(nodes[6].get('proto'), 'https')
1531
+ self.eq(nodes[6].get('path'), '')
1532
+ self.eq(nodes[6].get('params'), '')
1533
+ self.eq(nodes[6].get('ipv6'), '2010:836b:4179::836b:4179')
1534
+ self.eq(nodes[6].get('port'), 443)
1535
+
1474
1536
  async def test_url_file(self):
1475
1537
 
1476
1538
  async with self.getTestCore() as core: