synapse 2.208.0__py311-none-any.whl → 2.210.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/lib/cell.py +14 -4
- synapse/lib/coro.py +5 -0
- synapse/lib/json.py +48 -22
- synapse/lib/layer.py +23 -1
- synapse/lib/nexus.py +6 -0
- synapse/lib/rstorm.py +3 -1
- synapse/lib/storm.py +10 -2
- synapse/lib/stormlib/auth.py +6 -0
- synapse/lib/stormlib/notifications.py +12 -2
- synapse/lib/stormtypes.py +8 -0
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +19 -6
- synapse/models/entity.py +26 -0
- synapse/models/inet.py +11 -0
- synapse/models/person.py +9 -2
- synapse/tests/test_cortex.py +3 -3
- synapse/tests/test_lib_aha.py +1 -1
- synapse/tests/test_lib_cell.py +28 -8
- synapse/tests/test_lib_coro.py +23 -0
- synapse/tests/test_lib_json.py +41 -16
- synapse/tests/test_lib_rstorm.py +4 -3
- synapse/tests/test_lib_stormtypes.py +135 -3
- synapse/tests/test_lib_view.py +22 -0
- synapse/tests/test_model_entity.py +21 -0
- synapse/tests/test_model_gov_intl.py +2 -2
- synapse/tests/test_model_inet.py +15 -0
- synapse/tests/test_model_media.py +1 -0
- synapse/tests/test_model_person.py +12 -0
- synapse/tests/test_telepath.py +52 -41
- synapse/tests/test_tools_aha.py +7 -8
- synapse/tests/utils.py +1 -1
- synapse/tools/aha/clone.py +7 -1
- synapse/tools/aha/easycert.py +37 -42
- synapse/tools/aha/enroll.py +7 -1
- synapse/tools/aha/list.py +60 -65
- synapse/tools/aha/mirror.py +7 -1
- synapse/tools/aha/provision/service.py +7 -1
- synapse/tools/aha/provision/user.py +7 -1
- synapse/tools/apikey.py +8 -1
- synapse/tools/axon2axon.py +7 -1
- synapse/tools/cellauth.py +6 -5
- synapse/tools/cmdr.py +2 -1
- synapse/tools/csvtool.py +7 -2
- synapse/tools/feed.py +8 -2
- synapse/tools/genpkg.py +7 -1
- synapse/tools/healthcheck.py +7 -1
- synapse/tools/livebackup.py +7 -3
- synapse/tools/modrole.py +7 -1
- synapse/tools/moduser.py +7 -2
- synapse/tools/promote.py +7 -3
- synapse/tools/pullfile.py +6 -1
- synapse/tools/pushfile.py +7 -1
- synapse/tools/reload.py +7 -4
- synapse/tools/snapshot.py +7 -1
- synapse/tools/storm.py +7 -1
- {synapse-2.208.0.dist-info → synapse-2.210.0.dist-info}/METADATA +2 -2
- {synapse-2.208.0.dist-info → synapse-2.210.0.dist-info}/RECORD +60 -59
- {synapse-2.208.0.dist-info → synapse-2.210.0.dist-info}/WHEEL +1 -1
- {synapse-2.208.0.dist-info → synapse-2.210.0.dist-info}/licenses/LICENSE +0 -0
- {synapse-2.208.0.dist-info → synapse-2.210.0.dist-info}/top_level.txt +0 -0
synapse/tests/test_lib_cell.py
CHANGED
|
@@ -2238,7 +2238,7 @@ class CellTest(s_t_utils.SynTest):
|
|
|
2238
2238
|
self.false(core00.isactive)
|
|
2239
2239
|
|
|
2240
2240
|
modinfo = s_common.yamlload(core00.dirn, 'cell.mods.yaml')
|
|
2241
|
-
self.
|
|
2241
|
+
self.eq('aha://root@core...', modinfo.get('mirror', ''))
|
|
2242
2242
|
modinfo = s_common.yamlload(core01.dirn, 'cell.mods.yaml')
|
|
2243
2243
|
self.none(modinfo.get('mirror'))
|
|
2244
2244
|
|
|
@@ -2321,7 +2321,7 @@ class CellTest(s_t_utils.SynTest):
|
|
|
2321
2321
|
self.false(core00.isactive)
|
|
2322
2322
|
|
|
2323
2323
|
modinfo = s_common.yamlload(core00.dirn, 'cell.mods.yaml')
|
|
2324
|
-
self.
|
|
2324
|
+
self.eq('aha://root@core...', modinfo.get('mirror', ''))
|
|
2325
2325
|
modinfo = s_common.yamlload(core01.dirn, 'cell.mods.yaml')
|
|
2326
2326
|
self.none(modinfo.get('mirror'))
|
|
2327
2327
|
|
|
@@ -2333,7 +2333,7 @@ class CellTest(s_t_utils.SynTest):
|
|
|
2333
2333
|
modinfo = s_common.yamlload(core00.dirn, 'cell.mods.yaml')
|
|
2334
2334
|
self.none(modinfo.get('mirror'))
|
|
2335
2335
|
modinfo = s_common.yamlload(core01.dirn, 'cell.mods.yaml')
|
|
2336
|
-
self.
|
|
2336
|
+
self.eq('aha://root@core...', modinfo.get('mirror', ''))
|
|
2337
2337
|
|
|
2338
2338
|
# Backup the mirror (core01) which points to the core00
|
|
2339
2339
|
async with await axon00.upload() as upfd:
|
|
@@ -3285,6 +3285,7 @@ class CellTest(s_t_utils.SynTest):
|
|
|
3285
3285
|
dirn00 = s_common.genpath(dirn, '00.cell')
|
|
3286
3286
|
dirn01 = s_common.genpath(dirn, '01.cell')
|
|
3287
3287
|
dirn02 = s_common.genpath(dirn, '02.cell')
|
|
3288
|
+
dirn0002 = s_common.genpath(dirn, '00.02.cell')
|
|
3288
3289
|
|
|
3289
3290
|
cell00 = await base.enter_context(self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=dirn00))
|
|
3290
3291
|
cell01 = await base.enter_context(self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=dirn01,
|
|
@@ -3301,24 +3302,43 @@ class CellTest(s_t_utils.SynTest):
|
|
|
3301
3302
|
await cell01.handoff('some://url')
|
|
3302
3303
|
self.isin('01.cell is not the current leader', cm.exception.get('mesg'))
|
|
3303
3304
|
|
|
3304
|
-
#
|
|
3305
|
-
# control over the topology update is available during the promotion process.
|
|
3306
|
-
# Promote 02.cell -> Promote 01.cell -> Promote 00.cell -> BadState exception
|
|
3305
|
+
# Promote 02.cell -> Promote 01.cell -> Promote 00.cell, without breaking the configured topology
|
|
3307
3306
|
await cell02.promote(graceful=True)
|
|
3308
3307
|
self.false(cell00.isactive)
|
|
3308
|
+
self.eq(cell00.conf.get('mirror'), 'aha://root@cell...')
|
|
3309
3309
|
self.false(cell01.isactive)
|
|
3310
|
+
self.eq(cell01.conf.get('mirror'), 'aha://root@cell...')
|
|
3310
3311
|
self.true(cell02.isactive)
|
|
3312
|
+
self.none(cell02.conf.get('mirror'))
|
|
3311
3313
|
await cell02.sync()
|
|
3312
3314
|
|
|
3313
3315
|
await cell01.promote(graceful=True)
|
|
3314
3316
|
self.false(cell00.isactive)
|
|
3317
|
+
self.eq(cell00.conf.get('mirror'), 'aha://root@cell...')
|
|
3315
3318
|
self.true(cell01.isactive)
|
|
3319
|
+
self.none(cell01.conf.get('mirror'))
|
|
3316
3320
|
self.false(cell02.isactive)
|
|
3321
|
+
self.eq(cell02.conf.get('mirror'), 'aha://root@cell...')
|
|
3317
3322
|
await cell02.sync()
|
|
3318
3323
|
|
|
3324
|
+
await cell00.promote(graceful=True)
|
|
3325
|
+
self.true(cell00.isactive)
|
|
3326
|
+
self.none(cell00.conf.get('mirror'))
|
|
3327
|
+
self.false(cell01.isactive)
|
|
3328
|
+
self.eq(cell01.conf.get('mirror'), 'aha://root@cell...')
|
|
3329
|
+
self.false(cell02.isactive)
|
|
3330
|
+
self.eq(cell02.conf.get('mirror'), 'aha://root@cell...')
|
|
3331
|
+
await cell02.sync()
|
|
3332
|
+
|
|
3333
|
+
# A follower of a follower cannot be promoted up since its leader is not the active cell.
|
|
3334
|
+
cell0002 = await base.enter_context(self.addSvcToAha(aha, '00.02.cell', s_cell.Cell, dirn=dirn0002,
|
|
3335
|
+
provinfo={'mirror': '02.cell'}))
|
|
3336
|
+
self.false(cell0002.isactive)
|
|
3337
|
+
self.eq(cell0002.conf.get('mirror'), 'aha://root@02.cell...')
|
|
3319
3338
|
with self.raises(s_exc.BadState) as cm:
|
|
3320
|
-
await
|
|
3321
|
-
|
|
3339
|
+
await cell0002.promote(graceful=True)
|
|
3340
|
+
mesg = 'ahaname=02.cell is not the current leader and cannot handoff leadership to aha://00.02.cell.synapse.'
|
|
3341
|
+
self.isin(mesg, cm.exception.get('mesg'))
|
|
3322
3342
|
|
|
3323
3343
|
async def test_cell_get_aha_proxy(self):
|
|
3324
3344
|
|
synapse/tests/test_lib_coro.py
CHANGED
|
@@ -212,3 +212,26 @@ class CoroTest(s_t_utils.SynTest):
|
|
|
212
212
|
|
|
213
213
|
with self.raises(Exception):
|
|
214
214
|
await s_coro._parserforked(newp)
|
|
215
|
+
|
|
216
|
+
async def test_lib_coro_create_task(self):
|
|
217
|
+
|
|
218
|
+
async def sleep(n):
|
|
219
|
+
await asyncio.sleep(n)
|
|
220
|
+
if n == 0:
|
|
221
|
+
return 1 / 0
|
|
222
|
+
return n
|
|
223
|
+
|
|
224
|
+
s_coro.create_task(sleep(0.1))
|
|
225
|
+
s_coro.create_task(sleep(0.15))
|
|
226
|
+
s_coro.create_task(sleep(0.2))
|
|
227
|
+
self.len(3, s_coro.bgtasks)
|
|
228
|
+
results = await s_coro.await_bg_tasks()
|
|
229
|
+
self.eq(set(results), {0.1, 0.15, 0.2})
|
|
230
|
+
self.len(0, s_coro.bgtasks)
|
|
231
|
+
results = await s_coro.await_bg_tasks()
|
|
232
|
+
self.eq(results, [])
|
|
233
|
+
|
|
234
|
+
s_coro.create_task(sleep(0))
|
|
235
|
+
results = await s_coro.await_bg_tasks()
|
|
236
|
+
self.len(1, results)
|
|
237
|
+
self.isinstance(results[0], ZeroDivisionError)
|
synapse/tests/test_lib_json.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import io
|
|
2
2
|
import json
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import yyjson
|
|
5
5
|
|
|
6
6
|
import synapse.exc as s_exc
|
|
7
7
|
import synapse.common as s_common
|
|
@@ -44,9 +44,9 @@ class JsonTest(s_test.SynTest):
|
|
|
44
44
|
inval = '{"a": "😀\ud83d\ude47"}'
|
|
45
45
|
outval = {'a': '😀\ud83d\ude47'}
|
|
46
46
|
|
|
47
|
-
#
|
|
48
|
-
with self.raises(
|
|
49
|
-
|
|
47
|
+
# yyjson.loads fails because of the surrogate pairs
|
|
48
|
+
with self.raises(ValueError):
|
|
49
|
+
yyjson.loads(inval)
|
|
50
50
|
|
|
51
51
|
# stdlib json.loads passes because of voodoo magic
|
|
52
52
|
self.eq(outval, json.loads(inval))
|
|
@@ -63,9 +63,9 @@ class JsonTest(s_test.SynTest):
|
|
|
63
63
|
inval = {'a': '😀\ud83d\ude47'}
|
|
64
64
|
outval = b'{"a": "\\ud83d\\ude00\\ud83d\\ude47"}'
|
|
65
65
|
|
|
66
|
-
#
|
|
67
|
-
with self.raises(
|
|
68
|
-
|
|
66
|
+
# yyjson.dumps fails because of the surrogate pairs
|
|
67
|
+
with self.raises(UnicodeEncodeError):
|
|
68
|
+
yyjson.dumps(inval)
|
|
69
69
|
|
|
70
70
|
# stdlib json.dumps passes because of voodoo magic
|
|
71
71
|
self.eq(outval.decode(), json.dumps(inval))
|
|
@@ -85,15 +85,15 @@ class JsonTest(s_test.SynTest):
|
|
|
85
85
|
|
|
86
86
|
with self.raises(s_exc.MustBeJsonSafe) as exc:
|
|
87
87
|
s_json.dumps({}.items())
|
|
88
|
-
self.eq(exc.exception.get('mesg'), '
|
|
88
|
+
self.eq(exc.exception.get('mesg'), "TypeError: Object of type 'dict_items' is not JSON serializable")
|
|
89
89
|
|
|
90
90
|
with self.raises(s_exc.MustBeJsonSafe) as exc:
|
|
91
91
|
s_json.dumps({1: 'foo'})
|
|
92
|
-
self.eq(exc.exception.get('mesg'),
|
|
92
|
+
self.eq(exc.exception.get('mesg'), "TypeError: Dictionary keys must be strings")
|
|
93
93
|
|
|
94
94
|
with self.raises(s_exc.MustBeJsonSafe) as exc:
|
|
95
95
|
s_json.dumps({'\ud83d\ude47': {}.items()})
|
|
96
|
-
self.eq(exc.exception.get('mesg'),
|
|
96
|
+
self.eq(exc.exception.get('mesg'), "TypeError: Dictionary keys must be strings")
|
|
97
97
|
|
|
98
98
|
self.eq(b'"dict_items([])"', s_json.dumps({}.items(), default=str))
|
|
99
99
|
|
|
@@ -111,6 +111,20 @@ class JsonTest(s_test.SynTest):
|
|
|
111
111
|
s_json.dump({'c': 'd', 'a': 'b'}, buf)
|
|
112
112
|
self.eq(b'{"c":"d","a":"b"}', buf.getvalue())
|
|
113
113
|
|
|
114
|
+
async def test_lib_json_large_integers(self):
|
|
115
|
+
valu = [
|
|
116
|
+
1, 2,
|
|
117
|
+
-1, -2,
|
|
118
|
+
1.0, 2.0,
|
|
119
|
+
-1.0, -2.0,
|
|
120
|
+
2**63, -2**63, -2**63 - 1,
|
|
121
|
+
2**64, -2**64, 2**64 + 1,
|
|
122
|
+
2**128, 2**128 + 1,
|
|
123
|
+
-2**128, -2**128 - 1,
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
self.eq(valu, s_json.loads(s_json.dumps(valu)))
|
|
127
|
+
|
|
114
128
|
async def test_jsload(self):
|
|
115
129
|
with self.getTestDir() as dirn:
|
|
116
130
|
with s_common.genfile(dirn, 'jsload.json') as fp:
|
|
@@ -147,41 +161,52 @@ class JsonTest(s_test.SynTest):
|
|
|
147
161
|
|
|
148
162
|
buf = io.BytesIO()
|
|
149
163
|
|
|
164
|
+
msg = "Object of type '_io.BytesIO' is not JSON serializable"
|
|
150
165
|
with self.raises(s_exc.MustBeJsonSafe) as exc:
|
|
151
166
|
s_json.reqjsonsafe(buf)
|
|
152
|
-
self.isin(
|
|
167
|
+
self.isin(msg, exc.exception.get('mesg'))
|
|
153
168
|
|
|
154
169
|
with self.raises(s_exc.MustBeJsonSafe) as exc:
|
|
155
170
|
s_json.reqjsonsafe({'foo': buf})
|
|
156
|
-
self.isin(
|
|
171
|
+
self.isin(msg, exc.exception.get('mesg'))
|
|
157
172
|
|
|
158
173
|
with self.raises(s_exc.MustBeJsonSafe) as exc:
|
|
159
174
|
s_json.reqjsonsafe(['foo', buf])
|
|
160
|
-
self.isin(
|
|
175
|
+
self.isin(msg, exc.exception.get('mesg'))
|
|
161
176
|
|
|
162
177
|
items = (
|
|
163
178
|
(None, None),
|
|
164
179
|
(1234, None),
|
|
165
180
|
('1234', None),
|
|
181
|
+
('1234"', None),
|
|
166
182
|
({'asdf': 'haha'}, None),
|
|
167
183
|
({'a': (1,), 'b': [{'': 4}, 56, None, {'t': True, 'f': False}, 'oh my']}, None),
|
|
168
184
|
(b'1234', s_exc.MustBeJsonSafe),
|
|
185
|
+
(b'1234"', s_exc.MustBeJsonSafe),
|
|
186
|
+
({'a': float('nan')}, s_exc.MustBeJsonSafe),
|
|
169
187
|
({'a': 'a', 2: 2}, s_exc.MustBeJsonSafe),
|
|
170
188
|
({'a', 'b', 'c'}, s_exc.MustBeJsonSafe),
|
|
171
189
|
(s_common.novalu, s_exc.MustBeJsonSafe),
|
|
172
190
|
)
|
|
173
191
|
for (item, eret) in items:
|
|
174
192
|
if eret is None:
|
|
175
|
-
self.none(s_json.reqjsonsafe(item))
|
|
193
|
+
self.none(s_json.reqjsonsafe(item), msg=item)
|
|
176
194
|
else:
|
|
177
195
|
with self.raises(eret):
|
|
178
196
|
s_json.reqjsonsafe(item)
|
|
179
197
|
|
|
180
|
-
text
|
|
198
|
+
for text in ['😀', 'asdf', 'asdf"', '"asdf']:
|
|
199
|
+
s_json.reqjsonsafe(text)
|
|
200
|
+
|
|
201
|
+
text = ['😀\ud83d\ude47']
|
|
181
202
|
s_json.reqjsonsafe(text)
|
|
182
203
|
with self.raises(s_exc.MustBeJsonSafe) as exc:
|
|
183
204
|
s_json.reqjsonsafe(text, strict=True)
|
|
184
|
-
self.eq(exc.exception.get('mesg'), '
|
|
205
|
+
self.eq(exc.exception.get('mesg'), "'utf-8' codec can't encode characters in position 1-2: surrogates not allowed")
|
|
206
|
+
|
|
207
|
+
with self.raises(s_exc.MustBeJsonSafe) as exc:
|
|
208
|
+
s_json.reqjsonsafe(b'1234', strict=True)
|
|
209
|
+
self.eq(exc.exception.get('mesg'), 'Object of type bytes is not JSON serializable')
|
|
185
210
|
|
|
186
211
|
async def test_lib_json_data_at_rest(self):
|
|
187
212
|
async with self.getRegrCore('json-data') as core:
|
synapse/tests/test_lib_rstorm.py
CHANGED
|
@@ -119,7 +119,7 @@ clear_storm_opts = '''
|
|
|
119
119
|
.. storm-cortex:: default
|
|
120
120
|
.. storm-opts:: {"vars": {"foobar": "bar"}}
|
|
121
121
|
.. storm-clear-http:: true
|
|
122
|
-
.. storm:: $lib.print($
|
|
122
|
+
.. storm:: $lib.print(`{$foobar}bizboz`)
|
|
123
123
|
'''
|
|
124
124
|
|
|
125
125
|
stormenv = '''
|
|
@@ -381,8 +381,9 @@ class RStormLibTest(s_test.SynTest):
|
|
|
381
381
|
path = s_common.genpath(dirn, 'clear_storm_opts.rst')
|
|
382
382
|
with s_common.genfile(path) as fd:
|
|
383
383
|
fd.write(clear_storm_opts.encode())
|
|
384
|
-
with self.raises(s_exc.StormRuntimeError):
|
|
385
|
-
|
|
384
|
+
with self.raises(s_exc.StormRuntimeError) as cm:
|
|
385
|
+
await get_rst_text(path)
|
|
386
|
+
self.eq('Missing variable: foobar', cm.exception.get('mesg'))
|
|
386
387
|
|
|
387
388
|
# boom1 test
|
|
388
389
|
path = s_common.genpath(dirn, 'boom1.rst')
|
|
@@ -3802,7 +3802,6 @@ class StormTypesTest(s_test.SynTest):
|
|
|
3802
3802
|
async with self.getTestCore() as core:
|
|
3803
3803
|
async with self.getTestCore() as core2:
|
|
3804
3804
|
|
|
3805
|
-
await core2.nodes('[ inet:ipv4=1.2.3.4 ]')
|
|
3806
3805
|
url = core2.getLocalUrl('*/layer')
|
|
3807
3806
|
|
|
3808
3807
|
layriden = core2.view.layers[0].iden
|
|
@@ -3819,8 +3818,141 @@ class StormTypesTest(s_test.SynTest):
|
|
|
3819
3818
|
|
|
3820
3819
|
layr = core.getLayer(uplayr)
|
|
3821
3820
|
|
|
3822
|
-
|
|
3823
|
-
|
|
3821
|
+
async def query(q):
|
|
3822
|
+
'''
|
|
3823
|
+
Run a query on core2 and wait for it to sync to layr from core
|
|
3824
|
+
'''
|
|
3825
|
+
nodes = await core2.nodes(q)
|
|
3826
|
+
offs = await core2.view.layers[0].getEditIndx()
|
|
3827
|
+
evnt = await layr.waitUpstreamOffs(layriden, offs)
|
|
3828
|
+
self.true(await asyncio.wait_for(evnt.wait(), timeout=6))
|
|
3829
|
+
return nodes
|
|
3830
|
+
|
|
3831
|
+
vdef = {
|
|
3832
|
+
'layers': [layr.iden]
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3835
|
+
view00 = await core.addView(vdef)
|
|
3836
|
+
self.nn(view00)
|
|
3837
|
+
|
|
3838
|
+
# No foobar in core
|
|
3839
|
+
opts = {'view': view00.get('iden')}
|
|
3840
|
+
nodes = await core.nodes('it:dev:str=foobar', opts=opts)
|
|
3841
|
+
self.len(0, nodes)
|
|
3842
|
+
|
|
3843
|
+
# Add foobar in core2
|
|
3844
|
+
nodes = await query('[ it:dev:str=foobar ]')
|
|
3845
|
+
self.len(1, nodes)
|
|
3846
|
+
|
|
3847
|
+
# foobar shows up in core
|
|
3848
|
+
nodes = await core.nodes('it:dev:str=foobar', opts=opts)
|
|
3849
|
+
self.len(1, nodes)
|
|
3850
|
+
|
|
3851
|
+
self.len(1, layr.activetasks)
|
|
3852
|
+
|
|
3853
|
+
# The upstream key only accepts null
|
|
3854
|
+
q = f'layer.set {uplayr} upstream (true)'
|
|
3855
|
+
msgs = await core.stormlist(q)
|
|
3856
|
+
self.stormIsInErr('Layer only supports setting "mirror" and "upstream" to null.', msgs)
|
|
3857
|
+
|
|
3858
|
+
with self.raises(s_exc.BadOptValu) as exc:
|
|
3859
|
+
await layr.setLayerInfo('upstream', False)
|
|
3860
|
+
self.eq(exc.exception.get('mesg'), 'Layer only supports setting "mirror" and "upstream" to None.', msgs)
|
|
3861
|
+
|
|
3862
|
+
# Now remove the upstream configuration
|
|
3863
|
+
q = f'layer.set {uplayr} upstream (null)'
|
|
3864
|
+
msgs = await core.stormlist(q)
|
|
3865
|
+
self.stormHasNoWarnErr(msgs)
|
|
3866
|
+
|
|
3867
|
+
layr = core.getLayer(uplayr)
|
|
3868
|
+
self.len(0, layr.activetasks)
|
|
3869
|
+
self.none(layr.layrinfo.get('upstream'))
|
|
3870
|
+
|
|
3871
|
+
with self.raises(TimeoutError):
|
|
3872
|
+
await query('[ it:dev:str=newp ]')
|
|
3873
|
+
|
|
3874
|
+
# No newp in core because layer upstream is disabled
|
|
3875
|
+
nodes = await core.nodes('it:dev:str=newp', opts=opts)
|
|
3876
|
+
self.len(0, nodes)
|
|
3877
|
+
|
|
3878
|
+
async def test_storm_lib_layer_mirror(self):
|
|
3879
|
+
async with self.getTestCore() as core:
|
|
3880
|
+
async with self.getTestCore() as core2:
|
|
3881
|
+
|
|
3882
|
+
url = core2.getLocalUrl('*/layer')
|
|
3883
|
+
|
|
3884
|
+
layers = set(core.layers.keys())
|
|
3885
|
+
q = f'layer.add --mirror {url}'
|
|
3886
|
+
mesgs = await core.stormlist(q)
|
|
3887
|
+
uplayr = list(set(core.layers.keys()) - layers)[0]
|
|
3888
|
+
|
|
3889
|
+
q = f'layer.set {uplayr} name "woot woot"'
|
|
3890
|
+
mesgs = await core.stormlist(q)
|
|
3891
|
+
self.stormIsInPrint('(name: woot woot)', mesgs)
|
|
3892
|
+
|
|
3893
|
+
layr = core.getLayer(uplayr)
|
|
3894
|
+
|
|
3895
|
+
async def query(q):
|
|
3896
|
+
'''
|
|
3897
|
+
Run a query on core2 and wait for it to sync to layr from core
|
|
3898
|
+
'''
|
|
3899
|
+
nodes = await core2.nodes(q)
|
|
3900
|
+
offs = await core2.view.layers[0].getEditOffs()
|
|
3901
|
+
self.true(await layr.waitEditOffs(offs, timeout=10))
|
|
3902
|
+
return nodes
|
|
3903
|
+
|
|
3904
|
+
vdef = {
|
|
3905
|
+
'layers': [layr.iden]
|
|
3906
|
+
}
|
|
3907
|
+
|
|
3908
|
+
view00 = await core.addView(vdef)
|
|
3909
|
+
self.nn(view00)
|
|
3910
|
+
|
|
3911
|
+
# No foobar in core
|
|
3912
|
+
opts = {'view': view00.get('iden')}
|
|
3913
|
+
nodes = await core.nodes('it:dev:str=foobar', opts=opts)
|
|
3914
|
+
self.len(0, nodes)
|
|
3915
|
+
|
|
3916
|
+
# Add foobar in core2
|
|
3917
|
+
nodes = await query('[ it:dev:str=foobar ]')
|
|
3918
|
+
self.len(1, nodes)
|
|
3919
|
+
|
|
3920
|
+
# foobar shows up in core
|
|
3921
|
+
nodes = await core.nodes('it:dev:str=foobar', opts=opts)
|
|
3922
|
+
self.len(1, nodes)
|
|
3923
|
+
|
|
3924
|
+
self.true(layr.ismirror)
|
|
3925
|
+
self.nn(layr.leadtask)
|
|
3926
|
+
self.nn(layr.leader)
|
|
3927
|
+
self.len(0, layr.activetasks)
|
|
3928
|
+
|
|
3929
|
+
# The mirror key only accepts null
|
|
3930
|
+
q = f'layer.set {uplayr} mirror (true)'
|
|
3931
|
+
msgs = await core.stormlist(q)
|
|
3932
|
+
self.stormIsInErr('Layer only supports setting "mirror" and "upstream" to null.', msgs)
|
|
3933
|
+
|
|
3934
|
+
with self.raises(s_exc.BadOptValu) as exc:
|
|
3935
|
+
await layr.setLayerInfo('mirror', False)
|
|
3936
|
+
self.eq(exc.exception.get('mesg'), 'Layer only supports setting "mirror" and "upstream" to None.', msgs)
|
|
3937
|
+
|
|
3938
|
+
# Now remove the mirror configuration
|
|
3939
|
+
q = f'layer.set {uplayr} mirror (null)'
|
|
3940
|
+
msgs = await core.stormlist(q)
|
|
3941
|
+
self.stormHasNoWarnErr(msgs)
|
|
3942
|
+
|
|
3943
|
+
layr = core.getLayer(uplayr)
|
|
3944
|
+
self.none(layr.layrinfo.get('mirror'))
|
|
3945
|
+
self.none(layr.leadtask)
|
|
3946
|
+
self.none(layr.leader)
|
|
3947
|
+
self.false(layr.ismirror)
|
|
3948
|
+
|
|
3949
|
+
# Add newp in core2
|
|
3950
|
+
nodes = await query('[ it:dev:str=newp ]')
|
|
3951
|
+
self.len(1, nodes)
|
|
3952
|
+
|
|
3953
|
+
# No newp in core because layer mirroring is disabled
|
|
3954
|
+
nodes = await core.nodes('it:dev:str=newp', opts=opts)
|
|
3955
|
+
self.len(0, nodes)
|
|
3824
3956
|
|
|
3825
3957
|
async def test_storm_lib_view(self):
|
|
3826
3958
|
|
synapse/tests/test_lib_view.py
CHANGED
|
@@ -310,6 +310,28 @@ class ViewTest(s_t_utils.SynTest):
|
|
|
310
310
|
# But not the same layer twice
|
|
311
311
|
await self.asyncraises(s_exc.DupIden, core.view.addLayer(layriden))
|
|
312
312
|
|
|
313
|
+
# Nodes with a large number of edge edits may be chunked by iterLayerNodeEdits
|
|
314
|
+
await core.nodes('[ test:str=foo ] for $i in $lib.range(102) {[ test:int=$i ]}')
|
|
315
|
+
|
|
316
|
+
vdef2 = await core.view.fork()
|
|
317
|
+
opts = {'view': vdef2['iden']}
|
|
318
|
+
await core.nodes('[ test:str=foo +(refs)> { for $i in $lib.range(102) { test:int=$i } } ]', opts=opts)
|
|
319
|
+
|
|
320
|
+
strt = core.nexsroot.nexslog.index()
|
|
321
|
+
await core.nodes('$lib.view.get().merge()', opts=opts)
|
|
322
|
+
|
|
323
|
+
self.len(102, await core.nodes('test:str=foo -(refs)> test:int'))
|
|
324
|
+
|
|
325
|
+
edits = [edit async for edit in core.nexsroot.nexslog.iter(strt)]
|
|
326
|
+
self.len(1, edits)
|
|
327
|
+
|
|
328
|
+
nodeedit = edits[0][1][2][0]
|
|
329
|
+
|
|
330
|
+
# We should have two chunks of edits for the same buid due to the number of edges
|
|
331
|
+
self.eq(nodeedit[0][0], nodeedit[1][0])
|
|
332
|
+
self.len(100, nodeedit[0][2])
|
|
333
|
+
self.len(2, nodeedit[1][2])
|
|
334
|
+
|
|
313
335
|
async def test_view_merge_ival(self):
|
|
314
336
|
|
|
315
337
|
async with self.getTestCore() as core:
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import synapse.tests.utils as s_test
|
|
2
|
+
|
|
3
|
+
class EntityModelTest(s_test.SynTest):
|
|
4
|
+
|
|
5
|
+
async def test_entity_relationship(self):
|
|
6
|
+
|
|
7
|
+
async with self.getTestCore() as core:
|
|
8
|
+
|
|
9
|
+
nodes = await core.nodes('''[
|
|
10
|
+
entity:relationship=*
|
|
11
|
+
:type=tasks
|
|
12
|
+
:period=(2022, ?)
|
|
13
|
+
:source={[ ou:org=({"name": "China Ministry of State Security (MSS)"}) ]}
|
|
14
|
+
:target={[ risk:threat=({"org:name": "APT34", "reporter:name": "vertex"}) ]}
|
|
15
|
+
]''')
|
|
16
|
+
|
|
17
|
+
self.len(1, nodes)
|
|
18
|
+
self.eq(nodes[0].get('type'), 'tasks.')
|
|
19
|
+
self.eq(nodes[0].get('period'), (1640995200000, 9223372036854775807))
|
|
20
|
+
self.eq(nodes[0].get('source'), ('ou:org', '3332a704ed21dc3274d5731acc54a0ee'))
|
|
21
|
+
self.eq(nodes[0].get('target'), ('risk:threat', 'e15738ebae52273300b51c08eaad3a36'))
|
synapse/tests/test_model_inet.py
CHANGED
|
@@ -3164,6 +3164,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3164
3164
|
:creator=$visiiden
|
|
3165
3165
|
:platform=$platiden
|
|
3166
3166
|
:instance=$instiden
|
|
3167
|
+
:topic=' My Topic '
|
|
3167
3168
|
]
|
|
3168
3169
|
'''
|
|
3169
3170
|
opts = {'vars': {
|
|
@@ -3175,6 +3176,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3175
3176
|
self.len(1, nodes)
|
|
3176
3177
|
self.eq(nodes[0].ndef, ('inet:service:channel', s_common.guid(('general', 'channel', 'vertex', 'slack'))))
|
|
3177
3178
|
self.eq(nodes[0].get('name'), 'general')
|
|
3179
|
+
self.eq(nodes[0].get('topic'), 'my topic')
|
|
3178
3180
|
self.eq(nodes[0].get('period'), (1420070400000, 9223372036854775807))
|
|
3179
3181
|
self.eq(nodes[0].get('creator'), visiacct.ndef[1])
|
|
3180
3182
|
self.eq(nodes[0].get('platform'), platform.ndef[1])
|
|
@@ -3243,12 +3245,18 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3243
3245
|
:group=$devsiden
|
|
3244
3246
|
:public=$lib.false
|
|
3245
3247
|
:repost=*
|
|
3248
|
+
:mentions=(
|
|
3249
|
+
(inet:service:group, $devsiden),
|
|
3250
|
+
(inet:service:account, $blckiden),
|
|
3251
|
+
(inet:service:account, $blckiden),
|
|
3252
|
+
)
|
|
3246
3253
|
)
|
|
3247
3254
|
|
|
3248
3255
|
(inet:service:message=(blackout, visi, 1715856900000, vertex, slack)
|
|
3249
3256
|
:type=chat.direct
|
|
3250
3257
|
:to=$visiiden
|
|
3251
3258
|
:public=$lib.false
|
|
3259
|
+
:mentions?=((inet:service:message:attachment, $atchiden),)
|
|
3252
3260
|
)
|
|
3253
3261
|
|
|
3254
3262
|
(inet:service:message=(blackout, general, 1715856900000, vertex, slack)
|
|
@@ -3296,10 +3304,15 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3296
3304
|
self.eq(nodes[0].get('group'), devsgrp.ndef[1])
|
|
3297
3305
|
self.false(nodes[0].get('public'))
|
|
3298
3306
|
self.eq(nodes[0].get('type'), 'chat.group.')
|
|
3307
|
+
self.eq(
|
|
3308
|
+
nodes[0].get('mentions'),
|
|
3309
|
+
(('inet:service:account', blckacct.ndef[1]), ('inet:service:group', devsgrp.ndef[1]))
|
|
3310
|
+
)
|
|
3299
3311
|
|
|
3300
3312
|
self.eq(nodes[1].get('to'), visiacct.ndef[1])
|
|
3301
3313
|
self.false(nodes[1].get('public'))
|
|
3302
3314
|
self.eq(nodes[1].get('type'), 'chat.direct.')
|
|
3315
|
+
self.none(nodes[1].get('mentions'))
|
|
3303
3316
|
|
|
3304
3317
|
self.eq(nodes[2].get('channel'), gnrlchan.ndef[1])
|
|
3305
3318
|
self.true(nodes[2].get('public'))
|
|
@@ -3397,6 +3410,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3397
3410
|
q = '''
|
|
3398
3411
|
[ inet:service:message=(visi, says, relax)
|
|
3399
3412
|
:title="Hehe Haha"
|
|
3413
|
+
:hashtags="#hehe,#haha,#hehe"
|
|
3400
3414
|
:thread={[
|
|
3401
3415
|
inet:service:thread=*
|
|
3402
3416
|
:title="Woot Woot"
|
|
@@ -3410,6 +3424,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3410
3424
|
'''
|
|
3411
3425
|
nodes = await core.nodes(q)
|
|
3412
3426
|
self.len(1, nodes)
|
|
3427
|
+
self.eq(['#haha', '#hehe'], nodes[0].get('hashtags'))
|
|
3413
3428
|
self.len(1, await core.nodes('inet:service:message=(visi, says, hello) -> inet:service:thread:message'))
|
|
3414
3429
|
self.len(1, await core.nodes('''
|
|
3415
3430
|
inet:service:message:title="hehe haha"
|
|
@@ -151,6 +151,10 @@ class PsModelTest(s_t_utils.SynTest):
|
|
|
151
151
|
'users': ('visi', 'invisigoth'),
|
|
152
152
|
'crypto:address': 'btc/1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2',
|
|
153
153
|
'langs': (lang00 := s_common.guid(),),
|
|
154
|
+
'banner': file0,
|
|
155
|
+
'passwd': 'hunter2',
|
|
156
|
+
'website': 'https://blogs.vertex.link/brutus',
|
|
157
|
+
'websites': ('https://foo.com', 'https://bar.com', 'https://foo.com'),
|
|
154
158
|
}
|
|
155
159
|
opts = {'vars': {'valu': con0, 'p': props}}
|
|
156
160
|
q = '''[(ps:contact=$valu
|
|
@@ -172,6 +176,10 @@ class PsModelTest(s_t_utils.SynTest):
|
|
|
172
176
|
:death:place=$p."death:place" :death:place:loc=$p."death:place:loc"
|
|
173
177
|
:death:place:name=$p."death:place:name"
|
|
174
178
|
:service:accounts=(*, *) :langs=$p.langs
|
|
179
|
+
:banner=$p.banner
|
|
180
|
+
:passwd=$p.passwd
|
|
181
|
+
:website=$p.website
|
|
182
|
+
:websites=$p.websites
|
|
175
183
|
)]'''
|
|
176
184
|
nodes = await core.nodes(q, opts=opts)
|
|
177
185
|
self.len(1, nodes)
|
|
@@ -215,6 +223,10 @@ class PsModelTest(s_t_utils.SynTest):
|
|
|
215
223
|
self.eq(node.get('death:place:loc'), 'us.va.reston')
|
|
216
224
|
self.eq(node.get('birth:place:name'), 'reston, va, usa, earth, sol, milkyway')
|
|
217
225
|
self.eq(node.get('death:place:name'), 'reston, va, usa, earth, sol, milkyway')
|
|
226
|
+
self.eq(node.get('banner'), file0)
|
|
227
|
+
self.eq(node.get('passwd'), 'hunter2')
|
|
228
|
+
self.eq(node.get('website'), 'https://blogs.vertex.link/brutus')
|
|
229
|
+
self.eq(node.get('websites'), ('https://bar.com', 'https://foo.com'))
|
|
218
230
|
self.len(1, await core.nodes('ps:contact :birth:place -> geo:place'))
|
|
219
231
|
self.len(1, await core.nodes('ps:contact :death:place -> geo:place'))
|
|
220
232
|
self.len(2, await core.nodes('ps:contact :service:accounts -> inet:service:account'))
|