synapse 2.197.0__py311-none-any.whl → 2.199.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.
- synapse/axon.py +3 -0
- synapse/common.py +3 -0
- synapse/cortex.py +1 -3
- synapse/lib/aha.py +3 -0
- synapse/lib/ast.py +277 -165
- synapse/lib/auth.py +39 -11
- synapse/lib/cell.py +22 -4
- synapse/lib/hive.py +2 -1
- synapse/lib/hiveauth.py +10 -1
- synapse/lib/jsonstor.py +6 -5
- synapse/lib/layer.py +6 -5
- synapse/lib/node.py +10 -4
- synapse/lib/parser.py +46 -21
- synapse/lib/schemas.py +13 -0
- synapse/lib/snap.py +112 -36
- synapse/lib/storm.lark +13 -11
- synapse/lib/storm.py +11 -10
- synapse/lib/storm_format.py +3 -2
- synapse/lib/stormtypes.py +13 -4
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +2 -1
- synapse/models/infotech.py +18 -0
- synapse/models/risk.py +9 -0
- synapse/models/syn.py +18 -2
- synapse/tests/files/stormpkg/badendpoints.yaml +7 -0
- synapse/tests/files/stormpkg/testpkg.yaml +8 -0
- synapse/tests/test_cortex.py +108 -0
- synapse/tests/test_datamodel.py +27 -5
- synapse/tests/test_lib_aha.py +22 -12
- synapse/tests/test_lib_ast.py +57 -0
- synapse/tests/test_lib_auth.py +143 -2
- synapse/tests/test_lib_grammar.py +54 -2
- synapse/tests/test_lib_lmdbslab.py +24 -0
- synapse/tests/test_lib_storm.py +24 -0
- synapse/tests/test_lib_stormlib_macro.py +3 -3
- synapse/tests/test_lib_stormtypes.py +14 -2
- synapse/tests/test_model_infotech.py +13 -0
- synapse/tests/test_model_risk.py +6 -0
- synapse/tests/test_model_syn.py +58 -0
- synapse/tests/test_tools_genpkg.py +10 -0
- synapse/tests/utils.py +17 -0
- synapse/tools/hive/load.py +1 -0
- {synapse-2.197.0.dist-info → synapse-2.199.0.dist-info}/METADATA +1 -1
- {synapse-2.197.0.dist-info → synapse-2.199.0.dist-info}/RECORD +47 -46
- {synapse-2.197.0.dist-info → synapse-2.199.0.dist-info}/LICENSE +0 -0
- {synapse-2.197.0.dist-info → synapse-2.199.0.dist-info}/WHEEL +0 -0
- {synapse-2.197.0.dist-info → synapse-2.199.0.dist-info}/top_level.txt +0 -0
synapse/tests/test_cortex.py
CHANGED
|
@@ -1001,6 +1001,114 @@ class CortexTest(s_t_utils.SynTest):
|
|
|
1001
1001
|
self.eq(cm.exception.get('mesg'),
|
|
1002
1002
|
'walk operation expected a string or list. got: 0.')
|
|
1003
1003
|
|
|
1004
|
+
await core.nodes('[media:news=*]')
|
|
1005
|
+
|
|
1006
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} media:news [ +(refs)> $n ]')
|
|
1007
|
+
self.len(1, nodes)
|
|
1008
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1009
|
+
|
|
1010
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:str')
|
|
1011
|
+
self.len(1, nodes)
|
|
1012
|
+
|
|
1013
|
+
q = '''
|
|
1014
|
+
function foo() {
|
|
1015
|
+
for $x in $lib.range(5) {
|
|
1016
|
+
[ it:dev:int=$x ]
|
|
1017
|
+
emit $node
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
media:news [ +(refs)> $foo() ]
|
|
1021
|
+
'''
|
|
1022
|
+
nodes = await core.nodes(q)
|
|
1023
|
+
self.len(1, nodes)
|
|
1024
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1025
|
+
|
|
1026
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:int')
|
|
1027
|
+
self.len(5, nodes)
|
|
1028
|
+
|
|
1029
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} media:news [ -(refs)> $n ]')
|
|
1030
|
+
self.len(1, nodes)
|
|
1031
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1032
|
+
|
|
1033
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:str')
|
|
1034
|
+
self.len(0, nodes)
|
|
1035
|
+
|
|
1036
|
+
q = '''
|
|
1037
|
+
function foo() {
|
|
1038
|
+
for $x in $lib.range(5) {
|
|
1039
|
+
[ it:dev:int=$x ]
|
|
1040
|
+
emit $node
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
media:news [ -(refs)> $foo() ]
|
|
1044
|
+
'''
|
|
1045
|
+
nodes = await core.nodes(q)
|
|
1046
|
+
self.len(1, nodes)
|
|
1047
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1048
|
+
|
|
1049
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:int')
|
|
1050
|
+
self.len(0, nodes)
|
|
1051
|
+
|
|
1052
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} media:news [ <(refs)+ $n ]')
|
|
1053
|
+
self.len(1, nodes)
|
|
1054
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1055
|
+
|
|
1056
|
+
nodes = await core.nodes('media:news <(refs)- it:dev:str')
|
|
1057
|
+
self.len(1, nodes)
|
|
1058
|
+
|
|
1059
|
+
q = '''
|
|
1060
|
+
function foo() {
|
|
1061
|
+
for $x in $lib.range(5) {
|
|
1062
|
+
[ it:dev:int=$x ]
|
|
1063
|
+
emit $node
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
media:news [ <(refs)+ $foo() ]
|
|
1067
|
+
'''
|
|
1068
|
+
nodes = await core.nodes(q)
|
|
1069
|
+
self.len(1, nodes)
|
|
1070
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1071
|
+
|
|
1072
|
+
nodes = await core.nodes('media:news <(refs)- it:dev:int')
|
|
1073
|
+
self.len(5, nodes)
|
|
1074
|
+
|
|
1075
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} media:news [ <(refs)- $n ]')
|
|
1076
|
+
self.len(1, nodes)
|
|
1077
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1078
|
+
|
|
1079
|
+
nodes = await core.nodes('media:news <(refs)- it:dev:str')
|
|
1080
|
+
self.len(0, nodes)
|
|
1081
|
+
|
|
1082
|
+
q = '''
|
|
1083
|
+
function foo() {
|
|
1084
|
+
for $x in $lib.range(5) {
|
|
1085
|
+
[ it:dev:int=$x ]
|
|
1086
|
+
emit $node
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
media:news [ <(refs)- $foo() ]
|
|
1090
|
+
'''
|
|
1091
|
+
nodes = await core.nodes(q)
|
|
1092
|
+
self.len(1, nodes)
|
|
1093
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1094
|
+
|
|
1095
|
+
nodes = await core.nodes('media:news <(refs)- it:dev:int')
|
|
1096
|
+
self.len(0, nodes)
|
|
1097
|
+
|
|
1098
|
+
await core.nodes('[media:news=*]')
|
|
1099
|
+
|
|
1100
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} $edge=refs media:news [ +($edge)> $n ]')
|
|
1101
|
+
self.len(2, nodes)
|
|
1102
|
+
|
|
1103
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:str')
|
|
1104
|
+
self.len(2, nodes)
|
|
1105
|
+
|
|
1106
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} $edge=refs media:news [ -($edge)> $n ]')
|
|
1107
|
+
self.len(2, nodes)
|
|
1108
|
+
|
|
1109
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:str')
|
|
1110
|
+
self.len(0, nodes)
|
|
1111
|
+
|
|
1004
1112
|
async def test_cortex_callstorm(self):
|
|
1005
1113
|
|
|
1006
1114
|
async with self.getTestCore(conf={'auth:passwd': 'root'}) as core:
|
synapse/tests/test_datamodel.py
CHANGED
|
@@ -338,11 +338,33 @@ class DataModelTest(s_t_utils.SynTest):
|
|
|
338
338
|
|
|
339
339
|
async def test_datamodel_locked_subs(self):
|
|
340
340
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
self.
|
|
341
|
+
conf = {'modules': [('synapse.tests.utils.DeprModule', {})]}
|
|
342
|
+
async with self.getTestCore(conf=conf) as core:
|
|
343
|
+
|
|
344
|
+
msgs = await core.stormlist('[ test:deprsub=bar :range=(1, 5) ]')
|
|
345
|
+
self.stormHasNoWarnErr(msgs)
|
|
346
|
+
|
|
347
|
+
msgs = await core.stormlist('[ test:deprsub2=(foo, (2, 6)) ]')
|
|
348
|
+
self.stormHasNoWarnErr(msgs)
|
|
349
|
+
|
|
350
|
+
nodes = await core.nodes('test:deprsub=bar')
|
|
351
|
+
self.eq(1, nodes[0].get('range:min'))
|
|
352
|
+
self.eq(5, nodes[0].get('range:max'))
|
|
353
|
+
|
|
354
|
+
nodes = await core.nodes('test:deprsub2=(foo, (2, 6))')
|
|
355
|
+
self.eq(2, nodes[0].get('range:min'))
|
|
356
|
+
self.eq(6, nodes[0].get('range:max'))
|
|
357
|
+
|
|
358
|
+
await core.setDeprLock('test:deprsub:range:min', True)
|
|
359
|
+
nodes = await core.nodes('[ test:deprsub=foo :range=(1, 5) ]')
|
|
360
|
+
self.none(nodes[0].get('range:min'))
|
|
361
|
+
self.eq(5, nodes[0].get('range:max'))
|
|
362
|
+
|
|
363
|
+
await core.nodes('test:deprsub2 | delnode')
|
|
364
|
+
await core.setDeprLock('test:deprsub2:range:max', True)
|
|
365
|
+
nodes = await core.nodes('[ test:deprsub2=(foo, (2, 6)) ]')
|
|
366
|
+
self.none(nodes[0].get('range:max'))
|
|
367
|
+
self.eq(2, nodes[0].get('range:min'))
|
|
346
368
|
|
|
347
369
|
def test_datamodel_schema_basetypes(self):
|
|
348
370
|
# N.B. This test is to keep synapse.lib.schemas.datamodel_basetypes const
|
synapse/tests/test_lib_aha.py
CHANGED
|
@@ -133,13 +133,18 @@ class AhaTest(s_test.SynTest):
|
|
|
133
133
|
with self.getTestDir() as dirn:
|
|
134
134
|
cryo0_dirn = s_common.gendir(dirn, 'cryo0')
|
|
135
135
|
async with self.getTestAha(dirn=dirn) as aha:
|
|
136
|
+
|
|
137
|
+
replaymult = 1
|
|
138
|
+
if s_common.envbool('SYNDEV_NEXUS_REPLAY'):
|
|
139
|
+
replaymult = 2
|
|
140
|
+
|
|
136
141
|
purl = await aha.addAhaSvcProv('0.cryo')
|
|
137
142
|
|
|
138
|
-
wait00 = aha.waiter(1, 'aha:svcadd')
|
|
143
|
+
wait00 = aha.waiter(1 * replaymult, 'aha:svcadd')
|
|
139
144
|
|
|
140
145
|
conf = {'aha:provision': purl}
|
|
141
146
|
async with self.getTestCryo(dirn=cryo0_dirn, conf=conf) as cryo:
|
|
142
|
-
self.
|
|
147
|
+
self.len(1 * replaymult, await wait00.wait(timeout=6))
|
|
143
148
|
|
|
144
149
|
svc = await aha.getAhaSvc('0.cryo...')
|
|
145
150
|
linkiden = svc.get('svcinfo', {}).get('online')
|
|
@@ -147,16 +152,16 @@ class AhaTest(s_test.SynTest):
|
|
|
147
152
|
# Tear down the Aha cell.
|
|
148
153
|
await aha.__aexit__(None, None, None)
|
|
149
154
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
with self.getAsyncLoggerStream('synapse.lib.aha', f'Set [0.cryo.synapse] offline.') as stream:
|
|
156
|
+
async with self.getTestAha(dirn=dirn) as aha:
|
|
157
|
+
self.true(await asyncio.wait_for(stream.wait(), timeout=12))
|
|
158
|
+
svc = await aha.getAhaSvc('0.cryo...')
|
|
159
|
+
self.notin('online', svc.get('svcinfo'))
|
|
155
160
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
161
|
+
# Try setting something down a second time
|
|
162
|
+
await aha.setAhaSvcDown('0.cryo', linkiden, network='synapse')
|
|
163
|
+
svc = await aha.getAhaSvc('0.cryo...')
|
|
164
|
+
self.notin('online', svc.get('svcinfo'))
|
|
160
165
|
|
|
161
166
|
async def test_lib_aha_basics(self):
|
|
162
167
|
|
|
@@ -444,8 +449,13 @@ class AhaTest(s_test.SynTest):
|
|
|
444
449
|
|
|
445
450
|
async with self.getTestAha() as aha:
|
|
446
451
|
|
|
452
|
+
replaymult = 1
|
|
453
|
+
if s_common.envbool('SYNDEV_NEXUS_REPLAY'):
|
|
454
|
+
replaymult = 2
|
|
455
|
+
|
|
447
456
|
aha.testerr = True
|
|
448
457
|
wait00 = aha.waiter(1, 'aha:svcadd')
|
|
458
|
+
|
|
449
459
|
conf = {'aha:provision': await aha.addAhaSvcProv('0.cryo')}
|
|
450
460
|
async with self.getTestCryo(conf=conf) as cryo:
|
|
451
461
|
|
|
@@ -454,7 +464,7 @@ class AhaTest(s_test.SynTest):
|
|
|
454
464
|
svc = await aha.getAhaSvc('0.cryo...')
|
|
455
465
|
self.none(svc)
|
|
456
466
|
|
|
457
|
-
wait01 = aha.waiter(1, 'aha:svcadd')
|
|
467
|
+
wait01 = aha.waiter(1 * replaymult, 'aha:svcadd')
|
|
458
468
|
aha.testerr = False
|
|
459
469
|
|
|
460
470
|
self.nn(await wait01.wait(timeout=2))
|
synapse/tests/test_lib_ast.py
CHANGED
|
@@ -492,6 +492,63 @@ class AstTest(s_test.SynTest):
|
|
|
492
492
|
q = '$foo=newp [test:str=foo :hehe*$foo=heval]'
|
|
493
493
|
nodes = await core.nodes(q)
|
|
494
494
|
|
|
495
|
+
async def test_ast_setmultioper(self):
|
|
496
|
+
async with self.getTestCore() as core:
|
|
497
|
+
|
|
498
|
+
nodes = await core.nodes('[ test:arrayprop="*" :ints=(1,) ]')
|
|
499
|
+
self.eq(nodes[0].get('ints'), (1,))
|
|
500
|
+
|
|
501
|
+
nodes = await core.nodes('test:arrayprop [ :ints++=([3, 4]) ]')
|
|
502
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4))
|
|
503
|
+
|
|
504
|
+
nodes = await core.nodes('test:arrayprop [ :ints++=(null) ]')
|
|
505
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4))
|
|
506
|
+
|
|
507
|
+
nodes = await core.nodes('test:arrayprop [ :ints--=(null) ]')
|
|
508
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4))
|
|
509
|
+
|
|
510
|
+
nodes = await core.nodes('test:arrayprop [ :strs++=(foo, bar, baz) ]')
|
|
511
|
+
self.eq(nodes[0].get('strs'), ('foo', 'bar', 'baz'))
|
|
512
|
+
|
|
513
|
+
with self.raises(s_exc.BadTypeValu):
|
|
514
|
+
await core.nodes('test:arrayprop [ :ints++=(["newp", 5, 6]) ]')
|
|
515
|
+
|
|
516
|
+
nodes = await core.nodes('test:arrayprop [ :ints?++=(["newp", 5, 6]) ]')
|
|
517
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4, 5, 6))
|
|
518
|
+
|
|
519
|
+
with self.raises(s_exc.BadTypeValu):
|
|
520
|
+
await core.nodes('test:arrayprop [ :ints--=(["newp", 5, 6]) ]')
|
|
521
|
+
|
|
522
|
+
nodes = await core.nodes('test:arrayprop [ :ints?--=(["newp", 5, 6, 7]) ]')
|
|
523
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4))
|
|
524
|
+
|
|
525
|
+
nodes = await core.nodes('[ test:str=foo :ndefs++={[ test:str=bar ]} ]')
|
|
526
|
+
self.eq(nodes[0].get('ndefs'), (('test:str', 'bar'),))
|
|
527
|
+
|
|
528
|
+
nodes = await core.nodes('test:str=foo [ :ndefs++={[ test:str=baz test:str=faz ]} ]')
|
|
529
|
+
self.eq(nodes[0].get('ndefs'), (('test:str', 'bar'), ('test:str', 'baz'), ('test:str', 'faz')))
|
|
530
|
+
|
|
531
|
+
nodes = await core.nodes('test:str=foo [ :ndefs--={ test:str=baz test:str=faz } ]')
|
|
532
|
+
self.eq(nodes[0].get('ndefs'), (('test:str', 'bar'),))
|
|
533
|
+
|
|
534
|
+
with self.raises(s_exc.NoSuchProp):
|
|
535
|
+
await core.nodes('test:arrayprop [ :newp++=(["newp", 5, 6]) ]')
|
|
536
|
+
|
|
537
|
+
badq = [
|
|
538
|
+
'test:str [ :hehe++=([3, 4]) ]',
|
|
539
|
+
'test:str [ :hehe?++=([3, 4]) ]',
|
|
540
|
+
'test:str [ :hehe--=([3, 4]) ]',
|
|
541
|
+
'test:str [ :hehe?--=([3, 4]) ]',
|
|
542
|
+
'test:arrayprop [ :ints++=(3) ]',
|
|
543
|
+
'test:arrayprop [ :ints?++=(3) ]',
|
|
544
|
+
'test:arrayprop [ :ints--=(3) ]',
|
|
545
|
+
'test:arrayprop [ :ints?--=(3) ]',
|
|
546
|
+
]
|
|
547
|
+
|
|
548
|
+
for q in badq:
|
|
549
|
+
with self.raises(s_exc.StormRuntimeError):
|
|
550
|
+
await core.nodes(q)
|
|
551
|
+
|
|
495
552
|
async def test_ast_editparens(self):
|
|
496
553
|
|
|
497
554
|
async with self.getTestCore() as core:
|
synapse/tests/test_lib_auth.py
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import string
|
|
2
2
|
import pathlib
|
|
3
3
|
|
|
4
|
+
from unittest import mock
|
|
5
|
+
|
|
4
6
|
import synapse.exc as s_exc
|
|
7
|
+
import synapse.common as s_common
|
|
5
8
|
import synapse.telepath as s_telepath
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
import synapse.lib.auth as s_auth
|
|
11
|
+
import synapse.lib.cell as s_cell
|
|
12
|
+
import synapse.lib.lmdbslab as s_lmdbslab
|
|
7
13
|
|
|
8
14
|
import synapse.tests.utils as s_test
|
|
9
15
|
|
|
@@ -426,6 +432,126 @@ class AuthTest(s_test.SynTest):
|
|
|
426
432
|
with self.raises(s_exc.SchemaViolation):
|
|
427
433
|
await core.auth.allrole.setRules([(True, )])
|
|
428
434
|
|
|
435
|
+
async def test_auth_archived_locked_interaction(self):
|
|
436
|
+
|
|
437
|
+
# Check that we can't unlock an archived user
|
|
438
|
+
async with self.getTestCore() as core:
|
|
439
|
+
lowuser = await core.addUser('lowuser')
|
|
440
|
+
useriden = lowuser.get('iden')
|
|
441
|
+
|
|
442
|
+
await core.setUserArchived(useriden, True)
|
|
443
|
+
|
|
444
|
+
udef = await core.getUserDef(useriden)
|
|
445
|
+
self.true(udef.get('archived'))
|
|
446
|
+
self.true(udef.get('locked'))
|
|
447
|
+
|
|
448
|
+
# Unlocking an archived user is invalid
|
|
449
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
450
|
+
await core.setUserLocked(useriden, False)
|
|
451
|
+
self.eq(exc.exception.get('mesg'), 'Cannot unlock archived user.')
|
|
452
|
+
self.eq(exc.exception.get('user'), useriden)
|
|
453
|
+
self.eq(exc.exception.get('username'), 'lowuser')
|
|
454
|
+
|
|
455
|
+
# Check our cell migration that locks archived users
|
|
456
|
+
async with self.getRegrCore('unlocked-archived-users') as core:
|
|
457
|
+
for ii in range(10):
|
|
458
|
+
user = await core.getUserDefByName(f'lowuser{ii:02d}')
|
|
459
|
+
self.nn(user)
|
|
460
|
+
self.true(user.get('archived'))
|
|
461
|
+
self.true(user.get('locked'))
|
|
462
|
+
|
|
463
|
+
# Check behavior of upgraded mirrors and non-upgraded leader
|
|
464
|
+
async with self.getTestAha() as aha:
|
|
465
|
+
|
|
466
|
+
with self.getTestDir() as dirn:
|
|
467
|
+
path00 = s_common.gendir(dirn, 'cell00')
|
|
468
|
+
path01 = s_common.gendir(dirn, 'cell01')
|
|
469
|
+
|
|
470
|
+
with mock.patch('synapse.lib.cell.NEXUS_VERSION', (2, 177)):
|
|
471
|
+
async with self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=path00) as cell00:
|
|
472
|
+
lowuser = await cell00.addUser('lowuser')
|
|
473
|
+
useriden = lowuser.get('iden')
|
|
474
|
+
await cell00.setUserArchived(useriden, True)
|
|
475
|
+
|
|
476
|
+
with mock.patch('synapse.lib.cell.NEXUS_VERSION', (2, 198)):
|
|
477
|
+
async with self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=path01, provinfo={'mirror': 'cell'}) as cell01:
|
|
478
|
+
await cell01.sync()
|
|
479
|
+
udef = await cell01.getUserDef(useriden)
|
|
480
|
+
self.true(udef.get('locked'))
|
|
481
|
+
self.true(udef.get('archived'))
|
|
482
|
+
|
|
483
|
+
# Simulate a call to cell00.setUserLocked(useriden, False) to bypass
|
|
484
|
+
# the check in cell00.auth.setUserInfo()
|
|
485
|
+
await cell00.auth._push('user:info', useriden, 'locked', False)
|
|
486
|
+
await cell01.sync()
|
|
487
|
+
|
|
488
|
+
udef00 = await cell00.getUserDef(useriden)
|
|
489
|
+
self.true(udef00.get('archived'))
|
|
490
|
+
self.false(udef00.get('locked'))
|
|
491
|
+
|
|
492
|
+
udef01 = await cell01.getUserDef(useriden)
|
|
493
|
+
self.true(udef01.get('archived'))
|
|
494
|
+
self.false(udef01.get('locked'))
|
|
495
|
+
|
|
496
|
+
# Check that we don't blowup/schism if an upgraded mirror is behind a leader with a pending
|
|
497
|
+
# user:info event that unlocks an archived user
|
|
498
|
+
async with self.getTestAha() as aha:
|
|
499
|
+
|
|
500
|
+
with self.getTestDir() as dirn:
|
|
501
|
+
path00 = s_common.gendir(dirn, 'cell00')
|
|
502
|
+
path01 = s_common.gendir(dirn, 'cell01')
|
|
503
|
+
|
|
504
|
+
async with self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=path00) as cell00:
|
|
505
|
+
lowuser = await cell00.addUser('lowuser')
|
|
506
|
+
useriden = lowuser.get('iden')
|
|
507
|
+
await cell00.setUserLocked(useriden, True)
|
|
508
|
+
|
|
509
|
+
async with self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=path01, provinfo={'mirror': 'cell'}) as cell01:
|
|
510
|
+
await cell01.sync()
|
|
511
|
+
udef = await cell01.getUserDef(useriden)
|
|
512
|
+
self.true(udef.get('locked'))
|
|
513
|
+
self.false(udef.get('archived'))
|
|
514
|
+
|
|
515
|
+
# Set user locked while cell01 is offline so it will get the edit when it comes
|
|
516
|
+
# back
|
|
517
|
+
await cell00.setUserLocked(useriden, False)
|
|
518
|
+
await cell00.sync()
|
|
519
|
+
|
|
520
|
+
# Edit the slabs on both cells directly to archive the user
|
|
521
|
+
lmdb00 = s_common.genpath(path00, 'slabs', 'cell.lmdb')
|
|
522
|
+
lmdb01 = s_common.genpath(path01, 'slabs', 'cell.lmdb')
|
|
523
|
+
|
|
524
|
+
slab00 = await s_lmdbslab.Slab.anit(lmdb00, map_size=s_cell.SLAB_MAP_SIZE)
|
|
525
|
+
slab01 = await s_lmdbslab.Slab.anit(lmdb01, map_size=s_cell.SLAB_MAP_SIZE)
|
|
526
|
+
|
|
527
|
+
# Simulate the cell migration which locks archived users
|
|
528
|
+
for slab in (slab00, slab01):
|
|
529
|
+
authkv = slab.getSafeKeyVal('auth')
|
|
530
|
+
userkv = authkv.getSubKeyVal('user:info:')
|
|
531
|
+
|
|
532
|
+
info = userkv.get(useriden)
|
|
533
|
+
info['archived'] = True
|
|
534
|
+
info['locked'] = True
|
|
535
|
+
userkv.set(useriden, info)
|
|
536
|
+
|
|
537
|
+
await slab00.fini()
|
|
538
|
+
await slab01.fini()
|
|
539
|
+
|
|
540
|
+
# Spin the cells back up and wait for the edit to sync to cell01
|
|
541
|
+
async with self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=path00) as cell00:
|
|
542
|
+
udef = await cell00.getUserDef(useriden)
|
|
543
|
+
self.true(udef.get('archived'))
|
|
544
|
+
self.true(udef.get('locked'))
|
|
545
|
+
|
|
546
|
+
async with self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=path01, provinfo={'mirror': 'cell'}) as cell01:
|
|
547
|
+
await cell01.sync()
|
|
548
|
+
udef = await cell01.getUserDef(useriden)
|
|
549
|
+
self.true(udef.get('archived'))
|
|
550
|
+
self.true(udef.get('locked'))
|
|
551
|
+
|
|
552
|
+
self.ge(cell00.nexsvers, (2, 198))
|
|
553
|
+
self.ge(cell01.nexsvers, (2, 198))
|
|
554
|
+
|
|
429
555
|
async def test_auth_password_policy(self):
|
|
430
556
|
policy = {
|
|
431
557
|
'complexity': {
|
|
@@ -446,6 +572,21 @@ class AuthTest(s_test.SynTest):
|
|
|
446
572
|
pass3 = 'ZXN-pyv7ber-kzq2kgh'
|
|
447
573
|
|
|
448
574
|
conf = {'auth:passwd:policy': policy}
|
|
575
|
+
async with self.getTestCore(conf=conf) as core:
|
|
576
|
+
|
|
577
|
+
user = await core.auth.addUser('blackout@vertex.link')
|
|
578
|
+
|
|
579
|
+
self.none(user.info.get('policy:previous'))
|
|
580
|
+
await user.setPasswd(pass1, nexs=False)
|
|
581
|
+
await user.setPasswd(pass2, nexs=False)
|
|
582
|
+
await user.setPasswd(pass3, nexs=False)
|
|
583
|
+
self.len(2, user.info.get('policy:previous'))
|
|
584
|
+
|
|
585
|
+
await user.tryPasswd('newp')
|
|
586
|
+
self.eq(1, user.info.get('policy:attempts'))
|
|
587
|
+
await user.setLocked(False, logged=False)
|
|
588
|
+
self.eq(0, user.info.get('policy:attempts'))
|
|
589
|
+
|
|
449
590
|
async with self.getTestCore(conf=conf) as core:
|
|
450
591
|
auth = core.auth
|
|
451
592
|
self.nn(auth.policy)
|
|
@@ -708,7 +849,7 @@ class AuthTest(s_test.SynTest):
|
|
|
708
849
|
await core.callStorm('auth.role.addrule ninjas --gate $gate another.rule',
|
|
709
850
|
opts={'vars': {'gate': fork}})
|
|
710
851
|
|
|
711
|
-
user = await core.auth.getUserByName('lowuser') # type:
|
|
852
|
+
user = await core.auth.getUserByName('lowuser') # type: s_auth.User
|
|
712
853
|
self.false(user.allowed(('hehe',)))
|
|
713
854
|
self.false(user.allowed(('hehe',), deepdeny=True))
|
|
714
855
|
self.true(user.allowed(('hehe', 'haha')))
|
|
@@ -735,6 +735,17 @@ Queries = [
|
|
|
735
735
|
'[test:str=foo :$foo*$bar.baz=heval]',
|
|
736
736
|
'[test:str=foo :$foo*$bar.("baz")=heval]',
|
|
737
737
|
'[test:str=foo :$foo*$bar.baz()=heval]',
|
|
738
|
+
'[test:str=foo +(refs)> $n]',
|
|
739
|
+
'[test:str=foo +(refs)> $n.baz()]',
|
|
740
|
+
'[test:str=foo -(refs)> $n]',
|
|
741
|
+
'[test:str=foo <(refs)+ $n]',
|
|
742
|
+
'[test:str=foo <(refs)+ $n.baz()]',
|
|
743
|
+
'[test:str=foo <(refs)- $n]',
|
|
744
|
+
'[test:str=foo :bar++=([1, 2])]',
|
|
745
|
+
'[test:str=foo :$foo++=([1, 2])]',
|
|
746
|
+
'[test:str=foo :bar--=(foo, bar)]',
|
|
747
|
+
'[test:str=foo :bar?++=$baz]',
|
|
748
|
+
'[test:str=foo :bar?--={[it:dev:str=foo]}]',
|
|
738
749
|
]
|
|
739
750
|
|
|
740
751
|
# Generated with print_parse_list below
|
|
@@ -778,7 +789,7 @@ _ParseResults = [
|
|
|
778
789
|
'Query: [TryCatch: [Query: [LiftPropBy: [Const: inet:ipv4, Const: =, Const: asdf]], CatchBlock: [Const: TypeError, Const: err, Query: []]]]',
|
|
779
790
|
'Query: [TryCatch: [Query: [LiftPropBy: [Const: inet:ipv4, Const: =, Const: asdf]], CatchBlock: [Const: FooBar, Const: err, Query: []], CatchBlock: [Const: *, Const: err, Query: []]]]',
|
|
780
791
|
'Query: [LiftByArray: [Const: test:array, Const: =, Const: 1.2.3.4]]',
|
|
781
|
-
'Query: [CmdOper: [Const: macro.set, List: [Const: hehe, EmbedQuery:
|
|
792
|
+
'Query: [CmdOper: [Const: macro.set, List: [Const: hehe, EmbedQuery: inet:ipv4 ]]]',
|
|
782
793
|
'Query: [SetVarOper: [Const: q, EmbedQuery: #foo.bar]]',
|
|
783
794
|
'Query: [CmdOper: [Const: metrics.edits.byprop, List: [Const: inet:fqdn:domain, Const: --newv, VarDeref: [VarValue: [Const: lib], Const: null]]]]',
|
|
784
795
|
'Query: [CmdOper: [Const: tee, Const: ()]]',
|
|
@@ -1364,7 +1375,7 @@ _ParseResults = [
|
|
|
1364
1375
|
'Query: [SetVarOper: [Const: p, Const: names], LiftPropBy: [Const: ps:contact:name, Const: =, Const: foo], EditPropSet: [RelProp: [VarValue: [Const: p]], Const: ?-=, Const: bar]]',
|
|
1365
1376
|
'Query: [SetVarOper: [Const: pvar, Const: stuff], LiftProp: [Const: test:arrayprop], FiltOper: [Const: +, ArrayCond: [RelProp: [VarValue: [Const: pvar]], Const: =, Const: neato]]]',
|
|
1366
1377
|
'Query: [SetVarOper: [Const: pvar, Const: ints], LiftProp: [Const: test:arrayprop], FiltOper: [Const: +, ArrayCond: [RelProp: [VarValue: [Const: pvar]], Const: =, VarValue: [Const: othervar]]]]',
|
|
1367
|
-
'Query: [SetVarOper: [Const: foo, DollarExpr: [ExprDict: [Const: foo, EmbedQuery:
|
|
1378
|
+
'Query: [SetVarOper: [Const: foo, DollarExpr: [ExprDict: [Const: foo, EmbedQuery: inet:fqdn ]]]]',
|
|
1368
1379
|
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [Const: hehe], CondSetOper: [Const: unset], Const: heval]]',
|
|
1369
1380
|
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [Const: hehe], CondSetOper: [VarValue: [Const: foo]], Const: heval]]',
|
|
1370
1381
|
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [VarValue: [Const: foo]], CondSetOper: [Const: unset], Const: heval]]',
|
|
@@ -1372,6 +1383,17 @@ _ParseResults = [
|
|
|
1372
1383
|
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [VarValue: [Const: foo]], CondSetOper: [VarDeref: [VarValue: [Const: bar], Const: baz]], Const: heval]]',
|
|
1373
1384
|
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [VarValue: [Const: foo]], CondSetOper: [VarDeref: [VarValue: [Const: bar], DollarExpr: [Const: baz]]], Const: heval]]',
|
|
1374
1385
|
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [VarValue: [Const: foo]], CondSetOper: [FuncCall: [VarDeref: [VarValue: [Const: bar], Const: baz], CallArgs: [], CallKwargs: []]], Const: heval]]',
|
|
1386
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeAdd: [Const: refs, VarValue: [Const: n]]]',
|
|
1387
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeAdd: [Const: refs, FuncCall: [VarDeref: [VarValue: [Const: n], Const: baz], CallArgs: [], CallKwargs: []]]]',
|
|
1388
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeDel: [Const: refs, VarValue: [Const: n]]]',
|
|
1389
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeAdd: [Const: refs, VarValue: [Const: n]]]',
|
|
1390
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeAdd: [Const: refs, FuncCall: [VarDeref: [VarValue: [Const: n], Const: baz], CallArgs: [], CallKwargs: []]]]',
|
|
1391
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeDel: [Const: refs, VarValue: [Const: n]]]',
|
|
1392
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [Const: bar], Const: ++=, DollarExpr: [ExprList: [Const: 1, Const: 2]]]]',
|
|
1393
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [VarValue: [Const: foo]], Const: ++=, DollarExpr: [ExprList: [Const: 1, Const: 2]]]]',
|
|
1394
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [Const: bar], Const: --=, List: [Const: foo, Const: bar]]]',
|
|
1395
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [Const: bar], Const: ?++=, VarValue: [Const: baz]]]',
|
|
1396
|
+
'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [Const: bar], Const: ?--=, SubQuery: [Query: [EditNodeAdd: [FormName: [Const: it:dev:str], Const: =, Const: foo]]]]]',
|
|
1375
1397
|
]
|
|
1376
1398
|
|
|
1377
1399
|
class GrammarTest(s_t_utils.SynTest):
|
|
@@ -1663,6 +1685,27 @@ class GrammarTest(s_t_utils.SynTest):
|
|
|
1663
1685
|
errinfo = cm.exception.errinfo
|
|
1664
1686
|
self.eq(1, errinfo.get('mesg').count('#'))
|
|
1665
1687
|
|
|
1688
|
+
query = '$q = ${ /* secret comment */ $lib.print([hello) } $lib.macro.set(hehe, $q)'
|
|
1689
|
+
parser = s_parser.Parser(query)
|
|
1690
|
+
with self.raises(s_exc.BadSyntax) as cm:
|
|
1691
|
+
_ = parser.query()
|
|
1692
|
+
info = cm.exception.errinfo.get('highlight')
|
|
1693
|
+
self.eq((40, 41), info['offsets'])
|
|
1694
|
+
self.eq((1, 1), info['lines'])
|
|
1695
|
+
self.eq((41, 42), info['columns'])
|
|
1696
|
+
|
|
1697
|
+
query = """function test(hello) {
|
|
1698
|
+
+'''asdf
|
|
1699
|
+
asdfasdf'''
|
|
1700
|
+
}"""
|
|
1701
|
+
parser = s_parser.Parser(query)
|
|
1702
|
+
with self.raises(s_exc.BadSyntax) as cm:
|
|
1703
|
+
_ = parser.query()
|
|
1704
|
+
info = cm.exception.errinfo.get('highlight')
|
|
1705
|
+
self.eq((44, 83), info['offsets'])
|
|
1706
|
+
self.eq((2, 3), info['lines'])
|
|
1707
|
+
self.eq((22, 31), info['columns'])
|
|
1708
|
+
|
|
1666
1709
|
async def test_quotes(self):
|
|
1667
1710
|
|
|
1668
1711
|
# Test vectors
|
|
@@ -1766,6 +1809,15 @@ class GrammarTest(s_t_utils.SynTest):
|
|
|
1766
1809
|
self.false(s_grammar.isPropName('.hehe'))
|
|
1767
1810
|
self.false(s_grammar.isPropName('testcmd'))
|
|
1768
1811
|
|
|
1812
|
+
async def test_embed_offsets(self):
|
|
1813
|
+
|
|
1814
|
+
embq = ' /* secret comment */ $lib.print(hello) /* haha */ $lib.print(goodbye) /*foo */ '
|
|
1815
|
+
query = f'$q = ${{{embq}}} $lib.print($q)'
|
|
1816
|
+
parser = s_parser.Parser(query)
|
|
1817
|
+
q = parser.query()
|
|
1818
|
+
embed = q.kids[0].kids[1]
|
|
1819
|
+
self.eq(embq, embed.getAstText())
|
|
1820
|
+
|
|
1769
1821
|
def gen_parse_list():
|
|
1770
1822
|
'''
|
|
1771
1823
|
Prints out the Asts for a list of queries in order to compare ASTs between versions of parsers
|
|
@@ -371,6 +371,30 @@ class LmdbSlabTest(s_t_utils.SynTest):
|
|
|
371
371
|
'vm.dirty_ratio',
|
|
372
372
|
], msgs[0].get('sysctls', {}).keys())
|
|
373
373
|
|
|
374
|
+
async def test_lmdbslab_commit_over_max_xactops(self):
|
|
375
|
+
|
|
376
|
+
# Make sure that we don't confuse the periodic commit with the max replay log commit
|
|
377
|
+
with (self.getTestDir() as dirn,
|
|
378
|
+
patch('synapse.lib.lmdbslab.Slab.WARN_COMMIT_TIME_MS', 1),
|
|
379
|
+
patch('synapse.lib.lmdbslab.Slab.COMMIT_PERIOD', 100)
|
|
380
|
+
):
|
|
381
|
+
path = os.path.join(dirn, 'test.lmdb')
|
|
382
|
+
|
|
383
|
+
async with await s_lmdbslab.Slab.anit(path, max_replay_log=100, map_size=100_000_000) as slab:
|
|
384
|
+
foo = slab.initdb('foo', dupsort=True)
|
|
385
|
+
|
|
386
|
+
byts = b'\x00' * 256
|
|
387
|
+
for i in range(1000):
|
|
388
|
+
slab.put(b'\xff\xff\xff\xff' + s_common.guid(i).encode('utf8'), byts, db=foo)
|
|
389
|
+
await asyncio.sleep(0)
|
|
390
|
+
|
|
391
|
+
# Let the slab close and then grab its stats
|
|
392
|
+
stats = slab.statinfo()
|
|
393
|
+
commitstats = stats.get('commitstats', ())
|
|
394
|
+
self.gt(len(commitstats), 0)
|
|
395
|
+
commitstats = [x[1] for x in commitstats if x[1] != 0]
|
|
396
|
+
self.eq(commitstats, (100, 100, 100, 100, 100, 100, 100, 100, 100, 100))
|
|
397
|
+
|
|
374
398
|
async def test_lmdbslab_max_replay(self):
|
|
375
399
|
with self.getTestDir() as dirn:
|
|
376
400
|
path = os.path.join(dirn, 'test.lmdb')
|
synapse/tests/test_lib_storm.py
CHANGED
|
@@ -143,6 +143,26 @@ class StormTest(s_t_utils.SynTest):
|
|
|
143
143
|
self.eq(props.get('name'), 'org name 77')
|
|
144
144
|
self.eq(props.get('desc'), 'an org desc')
|
|
145
145
|
|
|
146
|
+
nodes = await core.nodes('ou:org=({"name": "the vertex project", "type": "lulz"})')
|
|
147
|
+
self.len(1, nodes)
|
|
148
|
+
orgn = nodes[0].ndef
|
|
149
|
+
self.eq(orgn, nodes11[0].ndef)
|
|
150
|
+
|
|
151
|
+
q = '[ ps:contact=* :org={ ou:org=({"name": "the vertex project", "type": "lulz"}) } ]'
|
|
152
|
+
nodes = await core.nodes(q)
|
|
153
|
+
self.len(1, nodes)
|
|
154
|
+
cont = nodes[0]
|
|
155
|
+
self.eq(cont.get('org'), orgn[1])
|
|
156
|
+
|
|
157
|
+
nodes = await core.nodes('ps:contact:org=({"name": "the vertex project", "type": "lulz"})')
|
|
158
|
+
self.len(1, nodes)
|
|
159
|
+
self.eq(nodes[0].ndef, cont.ndef)
|
|
160
|
+
|
|
161
|
+
self.len(0, await core.nodes('ps:contact:org=({"name": "vertex", "type": "newp"})'))
|
|
162
|
+
|
|
163
|
+
with self.raises(s_exc.BadTypeValu):
|
|
164
|
+
await core.nodes('inet:flow:from=({"name": "vertex", "type": "newp"})')
|
|
165
|
+
|
|
146
166
|
async def test_lib_storm_jsonexpr(self):
|
|
147
167
|
async with self.getTestCore() as core:
|
|
148
168
|
|
|
@@ -1737,6 +1757,10 @@ class StormTest(s_t_utils.SynTest):
|
|
|
1737
1757
|
msgs = await core.stormlist('test:ro | merge', opts=altview)
|
|
1738
1758
|
self.stormIsInWarn("Cannot merge read only property with conflicting value", msgs)
|
|
1739
1759
|
|
|
1760
|
+
await core.nodes('[ test:str=foo +(refs)> { for $i in $lib.range(1001) {[ test:int=$i ]}}]', opts=altview)
|
|
1761
|
+
await core.nodes('test:str=foo -(refs)+> * merge --apply', opts=altview)
|
|
1762
|
+
self.len(1001, await core.nodes('test:str=foo -(refs)> *'))
|
|
1763
|
+
|
|
1740
1764
|
async def test_storm_merge_stricterr(self):
|
|
1741
1765
|
|
|
1742
1766
|
conf = {'modules': [('synapse.tests.utils.DeprModule', {})]}
|
|
@@ -89,7 +89,7 @@ class MacroTest(s_test.SynTest):
|
|
|
89
89
|
name = 'v' * 491
|
|
90
90
|
q = '$lib.macro.set($name, ${ help }) return ( $lib.macro.get($name) )'
|
|
91
91
|
mdef = await core.callStorm(q, opts={'vars': {'name': name}})
|
|
92
|
-
self.eq(mdef.get('storm'), 'help')
|
|
92
|
+
self.eq(mdef.get('storm'), ' help ')
|
|
93
93
|
|
|
94
94
|
badname = 'v' * 492
|
|
95
95
|
with self.raises(s_exc.BadArg):
|
|
@@ -381,7 +381,7 @@ class MacroTest(s_test.SynTest):
|
|
|
381
381
|
self.eq('storm:macro:add', addmesg['data']['event'])
|
|
382
382
|
macro = addmesg['data']['info']['macro']
|
|
383
383
|
self.eq(macro['name'], 'foobar')
|
|
384
|
-
self.eq(macro['storm'], 'file:bytes | [+#neato]')
|
|
384
|
+
self.eq(macro['storm'], ' file:bytes | [+#neato] ')
|
|
385
385
|
self.ne(visi.iden, macro['user'])
|
|
386
386
|
self.ne(visi.iden, macro['creator'])
|
|
387
387
|
self.nn(macro['iden'])
|
|
@@ -390,7 +390,7 @@ class MacroTest(s_test.SynTest):
|
|
|
390
390
|
self.eq('storm:macro:mod', setmesg['data']['event'])
|
|
391
391
|
event = setmesg['data']['info']
|
|
392
392
|
self.nn(event['macro'])
|
|
393
|
-
self.eq(event['info']['storm'], 'inet:ipv4 | [+#burrito]')
|
|
393
|
+
self.eq(event['info']['storm'], ' inet:ipv4 | [+#burrito] ')
|
|
394
394
|
self.nn(event['info']['updated'])
|
|
395
395
|
|
|
396
396
|
modmesg = await sock.receive_json()
|