synapse 2.178.0__py311-none-any.whl → 2.180.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 (62) hide show
  1. synapse/cortex.py +166 -31
  2. synapse/datamodel.py +47 -1
  3. synapse/exc.py +1 -0
  4. synapse/lib/aha.py +2 -1
  5. synapse/lib/ast.py +110 -76
  6. synapse/lib/base.py +12 -3
  7. synapse/lib/cell.py +150 -11
  8. synapse/lib/coro.py +14 -0
  9. synapse/lib/drive.py +551 -0
  10. synapse/lib/layer.py +1 -1
  11. synapse/lib/lmdbslab.py +2 -0
  12. synapse/lib/modelrev.py +5 -1
  13. synapse/lib/node.py +14 -4
  14. synapse/lib/schemas.py +97 -0
  15. synapse/lib/snap.py +36 -11
  16. synapse/lib/storm.py +9 -5
  17. synapse/lib/stormhttp.py +1 -0
  18. synapse/lib/stormlib/modelext.py +29 -3
  19. synapse/lib/stormlib/stix.py +44 -17
  20. synapse/lib/stormlib/vault.py +2 -2
  21. synapse/lib/stormtypes.py +1 -1
  22. synapse/lib/types.py +9 -0
  23. synapse/lib/version.py +2 -2
  24. synapse/lookup/pe.py +303 -38
  25. synapse/models/auth.py +2 -0
  26. synapse/models/dns.py +24 -1
  27. synapse/models/geopol.py +3 -0
  28. synapse/models/geospace.py +4 -1
  29. synapse/models/inet.py +1 -0
  30. synapse/models/infotech.py +135 -92
  31. synapse/models/person.py +5 -2
  32. synapse/models/telco.py +3 -0
  33. synapse/tests/test_cortex.py +45 -1
  34. synapse/tests/test_lib_aha.py +17 -0
  35. synapse/tests/test_lib_ast.py +231 -0
  36. synapse/tests/test_lib_cell.py +225 -0
  37. synapse/tests/test_lib_coro.py +12 -0
  38. synapse/tests/test_lib_layer.py +22 -0
  39. synapse/tests/test_lib_modelrev.py +7 -0
  40. synapse/tests/test_lib_node.py +12 -1
  41. synapse/tests/test_lib_storm.py +32 -7
  42. synapse/tests/test_lib_stormhttp.py +40 -0
  43. synapse/tests/test_lib_stormlib_modelext.py +55 -3
  44. synapse/tests/test_lib_stormlib_stix.py +15 -0
  45. synapse/tests/test_lib_stormlib_vault.py +11 -1
  46. synapse/tests/test_lib_stormtypes.py +5 -0
  47. synapse/tests/test_lib_types.py +9 -0
  48. synapse/tests/test_model_dns.py +8 -0
  49. synapse/tests/test_model_geopol.py +2 -0
  50. synapse/tests/test_model_geospace.py +3 -1
  51. synapse/tests/test_model_inet.py +10 -1
  52. synapse/tests/test_model_infotech.py +47 -0
  53. synapse/tests/test_model_person.py +2 -0
  54. synapse/tests/test_model_syn.py +11 -0
  55. synapse/tests/test_model_telco.py +2 -1
  56. synapse/tests/test_utils_stormcov.py +1 -1
  57. synapse/tools/changelog.py +28 -0
  58. {synapse-2.178.0.dist-info → synapse-2.180.0.dist-info}/METADATA +1 -1
  59. {synapse-2.178.0.dist-info → synapse-2.180.0.dist-info}/RECORD +62 -61
  60. {synapse-2.178.0.dist-info → synapse-2.180.0.dist-info}/WHEEL +1 -1
  61. {synapse-2.178.0.dist-info → synapse-2.180.0.dist-info}/LICENSE +0 -0
  62. {synapse-2.178.0.dist-info → synapse-2.180.0.dist-info}/top_level.txt +0 -0
@@ -4100,3 +4100,234 @@ class AstTest(s_test.SynTest):
4100
4100
  q = 'media:news=(m0,) [-:published]'
4101
4101
  msgs = await core.stormlist(q, opts=aslow)
4102
4102
  self.stormIsInErr('must have permission node.prop.del.media:news.published', msgs)
4103
+
4104
+ async def test_ast_path_links(self):
4105
+
4106
+ async with self.getTestCore() as core: # type: s_cortex.Cortex
4107
+ guid = s_common.guid()
4108
+ opts = {'vars': {'guid': guid}}
4109
+
4110
+ burr = (await core.nodes('[test:comp=(1234, burrito)]'))[0]
4111
+ guid = (await core.nodes('[test:guid=$guid :size=176 :tick=now]', opts=opts))[0]
4112
+ edge = (await core.nodes('[test:edge=(("test:guid", $guid), ("test:str", abcd))]', opts=opts))[0]
4113
+ comp = (await core.nodes('[test:complexcomp=(1234, STUFF) +#foo.bar]'))[0]
4114
+ tstr = (await core.nodes('[test:str=foobar :bar=(test:ro, "ackbar") :ndefs=((test:guid, $guid), (test:auto, "auto"))]', opts=opts))[0]
4115
+ arry = (await core.nodes('[test:arrayprop=* :ints=(3245, 678) :strs=("foo", "bar", "foobar")]'))[0]
4116
+ ostr = (await core.nodes('test:str=foo [ :bar=(test:ro, "ackbar") :ndefs=((test:int, 176), )]'))[0]
4117
+ pstr = (await core.nodes('test:str=bar [ :ndefs=((test:guid, $guid), (test:auto, "auto"), (test:ro, "ackbar"))]', opts=opts))[0]
4118
+ (await core.nodes('[test:arrayform=(1234, 176)]'))[0]
4119
+ (await core.nodes('[test:arrayform=(3245, 678)]'))[0]
4120
+
4121
+ await core.nodes('test:int=176 [ <(seen)+ { test:guid } ]')
4122
+ await core.nodes('test:int=176 [ <(someedge)+ { test:guid } ]')
4123
+ await core.nodes('test:complexcomp [ <(refs)+ { test:arrayprop } ]')
4124
+ await core.nodes('test:complexcomp [ +(concerns)> { test:ro } ]')
4125
+ await core.nodes('test:edge [ <(seen)+ { test:guid } ]')
4126
+
4127
+ small = (await core.nodes('test:int=176'))[0]
4128
+ large = (await core.nodes('test:int=1234'))[0]
4129
+ auto = (await core.nodes('test:auto'))[0]
4130
+ basetag = (await core.nodes('syn:tag=foo'))[0]
4131
+ tag = (await core.nodes('syn:tag=foo.bar'))[0]
4132
+ ro = (await core.nodes('test:ro'))[0]
4133
+
4134
+ def _assert_edge(msgs, src, edge, nidx=0, eidx=0):
4135
+ nodes = [m[1] for m in msgs if m[0] == 'node']
4136
+ links = nodes[nidx][1].get('links')
4137
+ self.nn(links)
4138
+ self.lt(eidx, len(links))
4139
+ self.eq(links[eidx], (src.iden(), edge))
4140
+
4141
+ opts = {'links': True}
4142
+
4143
+ # non-runtsafe lift could be anything
4144
+ msgs = await core.stormlist('test:str=foobar $newform=$node.props.bar.0 *$newform', opts={'links': True, 'vars': {'form': 'inet:ipv4'}})
4145
+ _assert_edge(msgs, tstr, {'type': 'runtime'}, nidx=1)
4146
+
4147
+ # FormPivot
4148
+ # -> baz:ndef
4149
+ msgs = await core.stormlist('test:guid -> test:edge:n1', opts=opts)
4150
+ _assert_edge(msgs, guid, {'type': 'prop', 'prop': 'n1', 'reverse': True})
4151
+
4152
+ # plain old pivot
4153
+ msgs = await core.stormlist('test:int=176 -> test:guid:size', opts=opts)
4154
+ _assert_edge(msgs, small, {'type': 'prop', 'prop': 'size', 'reverse': True})
4155
+
4156
+ # graph edge dest form uses n1 automagically
4157
+ msgs = await core.stormlist('test:guid -> test:edge', opts=opts)
4158
+ _assert_edge(msgs, guid, {'type': 'prop', 'prop': 'n1', 'reverse': True})
4159
+
4160
+ # <syn:tag> -> <form>
4161
+ msgs = await core.stormlist('syn:tag=foo.bar -> test:complexcomp', opts=opts)
4162
+ _assert_edge(msgs, tag, {'type': 'tag', 'tag': 'foo.bar', 'reverse': True})
4163
+
4164
+ # source node is a graph edge, use n2
4165
+ msgs = await core.stormlist('test:edge -> test:str', opts=opts)
4166
+ _assert_edge(msgs, edge, {'type': 'prop', 'prop': 'n2'})
4167
+
4168
+ # refs out - prop
4169
+ msgs = await core.stormlist('test:complexcomp -> test:int', opts=opts)
4170
+ _assert_edge(msgs, comp, {'type': 'prop', 'prop': 'foo'})
4171
+
4172
+ # refs out - array
4173
+ msgs = await core.stormlist('test:arrayprop -> test:int', opts=opts)
4174
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'ints'})
4175
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'ints'}, nidx=1)
4176
+
4177
+ # refs out - ndef
4178
+ msgs = await core.stormlist('test:str -> test:ro', opts=opts)
4179
+ _assert_edge(msgs, pstr, {'type': 'prop', 'prop': 'ndefs'})
4180
+ _assert_edge(msgs, ostr, {'type': 'prop', 'prop': 'bar'}, nidx=1)
4181
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'bar'}, nidx=2)
4182
+
4183
+ # refs out - ndefarray
4184
+ msgs = await core.stormlist('test:str -> test:auto', opts=opts)
4185
+ _assert_edge(msgs, pstr, {'type': 'prop', 'prop': 'ndefs'})
4186
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'ndefs'}, nidx=1)
4187
+
4188
+ # reverse prop refs
4189
+ msgs = await core.stormlist('test:int -> test:complexcomp', opts=opts)
4190
+ _assert_edge(msgs, large, {'type': 'prop', 'prop': 'foo', 'reverse': True})
4191
+
4192
+ # reverse array refs
4193
+ msgs = await core.stormlist('test:int -> test:arrayprop', opts=opts)
4194
+ sixer = (await core.nodes('test:int=678'))[0]
4195
+ thou = (await core.nodes('test:int=3245'))[0]
4196
+ _assert_edge(msgs, sixer, {'type': 'prop', 'prop': 'ints', 'reverse': True})
4197
+ _assert_edge(msgs, thou, {'type': 'prop', 'prop': 'ints', 'reverse': True}, nidx=1)
4198
+
4199
+ # reverse ndef refs
4200
+ msgs = await core.stormlist('test:ro -> test:str', opts=opts)
4201
+ _assert_edge(msgs, ro, {'type': 'prop', 'prop': 'bar', 'reverse': True})
4202
+
4203
+ # reverse ndefarray refs
4204
+ msgs = await core.stormlist('test:auto -> test:str', opts=opts)
4205
+ _assert_edge(msgs, auto, {'type': 'prop', 'prop': 'ndefs', 'reverse': True})
4206
+
4207
+ # PivotOut syn:tag
4208
+ msgs = await core.stormlist('syn:tag -> *', opts=opts)
4209
+ _assert_edge(msgs, basetag, {'type': 'tag', 'tag': 'foo', 'reverse': True})
4210
+ _assert_edge(msgs, tag, {'type': 'tag', 'tag': 'foo.bar', 'reverse': True}, nidx=1)
4211
+
4212
+ # PivotOut edge uses n2 automatically
4213
+ msgs = await core.stormlist('test:edge -> *', opts=opts)
4214
+ _assert_edge(msgs, edge, {'type': 'prop', 'prop': 'n2'})
4215
+
4216
+ # PivotOut prop
4217
+ msgs = await core.stormlist('test:guid -> *', opts=opts)
4218
+ _assert_edge(msgs, guid, {'type': 'prop', 'prop': 'size'})
4219
+
4220
+ # PivotOut prop array
4221
+ msgs = await core.stormlist('test:arrayprop -> *', opts=opts)
4222
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'ints'})
4223
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'ints'}, nidx=1)
4224
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'strs'}, nidx=2)
4225
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'strs'}, nidx=3)
4226
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'strs'}, nidx=4)
4227
+
4228
+ # PivotOut prop ndef and ndef array
4229
+ msgs = await core.stormlist('test:str=foobar -> *', opts=opts)
4230
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'bar'})
4231
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'ndefs'}, nidx=1)
4232
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'ndefs'}, nidx=2)
4233
+
4234
+ # PivotToTags
4235
+ msgs = await core.stormlist('test:complexcomp -> #', opts=opts)
4236
+ _assert_edge(msgs, comp, {'type': 'tag', 'tag': 'foo.bar'})
4237
+
4238
+ # PivotIn prop
4239
+ msgs = await core.stormlist('test:int=176 <- *', opts=opts)
4240
+ _assert_edge(msgs, small, {'type': 'prop', 'prop': 'size', 'reverse': True})
4241
+
4242
+ # PivotIn array prop
4243
+ msgs = await core.stormlist('test:str=foobar <- *', opts=opts)
4244
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'strs', 'reverse': True})
4245
+
4246
+ # PivotIn edge uses n1 automatically
4247
+ msgs = await core.stormlist('test:edge <- *', opts=opts)
4248
+ _assert_edge(msgs, edge, {'type': 'prop', 'prop': 'n1', 'reverse': True})
4249
+
4250
+ # PivotIn ndef
4251
+ msgs = await core.stormlist('test:ro <- *', opts=opts)
4252
+ _assert_edge(msgs, ro, {'type': 'prop', 'prop': 'bar', 'reverse': True})
4253
+
4254
+ # PivotIn array ndef
4255
+ msgs = await core.stormlist('test:auto <- *', opts=opts)
4256
+ _assert_edge(msgs, auto, {'type': 'prop', 'prop': 'ndefs', 'reverse': True})
4257
+
4258
+ # PivotInFrom "<- edge"
4259
+ abcd = (await core.nodes('test:str=abcd'))[0]
4260
+ msgs = await core.stormlist('test:str <- test:edge', opts=opts)
4261
+ _assert_edge(msgs, abcd, {'type': 'prop', 'prop': 'n2', 'reverse': True})
4262
+
4263
+ # PivotInFrom "edge <- form"
4264
+ msgs = await core.stormlist('test:edge <- test:guid', opts=opts)
4265
+ _assert_edge(msgs, edge, {'type': 'prop', 'prop': 'n1', 'reverse': True})
4266
+
4267
+ # PropPivotOut prop
4268
+ msgs = await core.stormlist('test:guid :size -> *', opts=opts)
4269
+ _assert_edge(msgs, guid, {'type': 'prop', 'prop': 'size'})
4270
+
4271
+ # PropPivotOut ndef
4272
+ msgs = await core.stormlist('test:str=foobar :bar -> *', opts=opts)
4273
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'bar'})
4274
+
4275
+ # PropPivotOut array
4276
+ msgs = await core.stormlist('test:arrayprop :ints -> *', opts=opts)
4277
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'ints'})
4278
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'ints'}, nidx=1)
4279
+
4280
+ # PropPivotOut array ndef
4281
+ msgs = await core.stormlist('test:str=foobar :ndefs -> *', opts=opts)
4282
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'ndefs'})
4283
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'ndefs'}, nidx=1)
4284
+
4285
+ # PropPivot prop to form
4286
+ msgs = await core.stormlist('test:guid :size -> test:int', opts=opts)
4287
+ _assert_edge(msgs, guid, {'type': 'prop', 'prop': 'size'})
4288
+
4289
+ # PropPivot ndef prop
4290
+ msgs = await core.stormlist('test:str :bar -> test:ro', opts=opts)
4291
+ _assert_edge(msgs, ostr, {'type': 'prop', 'prop': 'bar'})
4292
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'bar'}, nidx=1)
4293
+
4294
+ # PropPivot array
4295
+ msgs = await core.stormlist('test:arrayprop :ints -> test:int', opts=opts)
4296
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'ints'})
4297
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'ints'}, nidx=1)
4298
+
4299
+ # PropPivot dst array primary prop
4300
+ msgs = await core.stormlist('test:guid :size -> test:arrayform', opts=opts)
4301
+ _assert_edge(msgs, guid, {'type': 'prop', 'prop': 'size'})
4302
+
4303
+ # PropPivot oops all arrays
4304
+ msgs = await core.stormlist('test:arrayprop :ints -> test:arrayform', opts=opts)
4305
+ _assert_edge(msgs, arry, {'type': 'prop', 'prop': 'ints'})
4306
+
4307
+ # PropPivot src ndef array
4308
+ msgs = await core.stormlist('test:str=foobar :ndefs -> test:guid', opts=opts)
4309
+ _assert_edge(msgs, tstr, {'type': 'prop', 'prop': 'ndefs'})
4310
+
4311
+ # prop to prop
4312
+ msgs = await core.stormlist('test:comp :hehe -> test:complexcomp:foo', opts=opts)
4313
+ _assert_edge(msgs, burr, {'type': 'prop', 'prop': 'hehe', 'dest': 'test:complexcomp:foo'})
4314
+
4315
+ # N1Walk
4316
+ msgs = await core.stormlist('test:arrayprop -(*)> *', opts=opts)
4317
+ _assert_edge(msgs, arry, {'type': 'edge', 'verb': 'refs'})
4318
+
4319
+ # N2Walk
4320
+ msgs = await core.stormlist('test:edge <(*)- *', opts=opts)
4321
+ _assert_edge(msgs, edge, {'type': 'edge', 'verb': 'seen', 'reverse': True})
4322
+
4323
+ # N1WalkNPivo
4324
+ msgs = await core.stormlist('test:complexcomp --> *', opts=opts)
4325
+ _assert_edge(msgs, comp, {'type': 'prop', 'prop': 'foo'})
4326
+ _assert_edge(msgs, comp, {'type': 'edge', 'verb': 'concerns'}, nidx=1)
4327
+
4328
+ # N2WalNkPivo
4329
+ msgs = await core.stormlist('test:int=176 <-- *', opts=opts)
4330
+ _assert_edge(msgs, small, {'type': 'prop', 'prop': 'size', 'reverse': True})
4331
+ _assert_edge(msgs, small, {'type': 'prop', 'prop': 'ndefs', 'reverse': True}, nidx=1)
4332
+ _assert_edge(msgs, small, {'type': 'edge', 'verb': 'seen', 'reverse': True}, nidx=2)
4333
+ _assert_edge(msgs, small, {'type': 'edge', 'verb': 'someedge', 'reverse': True}, nidx=3)
@@ -28,6 +28,7 @@ import synapse.lib.base as s_base
28
28
  import synapse.lib.cell as s_cell
29
29
  import synapse.lib.coro as s_coro
30
30
  import synapse.lib.link as s_link
31
+ import synapse.lib.drive as s_drive
31
32
  import synapse.lib.nexus as s_nexus
32
33
  import synapse.lib.certdir as s_certdir
33
34
  import synapse.lib.msgpack as s_msgpack
@@ -155,8 +156,217 @@ async def altAuthCtor(cell):
155
156
  cell.onfini(auth.fini)
156
157
  return auth
157
158
 
159
+ testDataSchema_v0 = {
160
+ 'type': 'object',
161
+ 'properties': {
162
+ 'type': {'type': 'string'},
163
+ 'size': {'type': 'number'},
164
+ },
165
+ 'required': ['type', 'size'],
166
+ 'additionalProperties': False,
167
+ }
168
+
169
+ testDataSchema_v1 = {
170
+ 'type': 'object',
171
+ 'properties': {
172
+ 'type': {'type': 'string'},
173
+ 'size': {'type': 'number'},
174
+ 'woot': {'type': 'string'},
175
+ },
176
+ 'required': ['type', 'size', 'woot'],
177
+ 'additionalProperties': False,
178
+ }
179
+
158
180
  class CellTest(s_t_utils.SynTest):
159
181
 
182
+ async def test_cell_drive(self):
183
+
184
+ async with self.getTestCell() as cell:
185
+
186
+ with self.raises(s_exc.BadName):
187
+ s_drive.reqValidName('A' * 512)
188
+
189
+ info = {'name': 'users'}
190
+ pathinfo = await cell.addDriveItem(info)
191
+
192
+ info = {'name': 'root'}
193
+ pathinfo = await cell.addDriveItem(info, path='users')
194
+
195
+ with self.raises(s_exc.DupIden):
196
+ await cell.drive.addItemInfo(pathinfo[-1], path='users')
197
+
198
+ rootdir = pathinfo[-1].get('iden')
199
+ self.eq(0, pathinfo[-1].get('kids'))
200
+
201
+ info = {'name': 'win32k.sys', 'type': 'hehe'}
202
+ with self.raises(s_exc.NoSuchType):
203
+ info = await cell.addDriveItem(info, reldir=rootdir)
204
+
205
+ infos = [i async for i in cell.getDriveKids(s_drive.rootdir)]
206
+ self.len(1, infos)
207
+ self.eq(1, infos[0].get('kids'))
208
+ self.eq('users', infos[0].get('name'))
209
+
210
+ # TODO how to handle iden match with additional property mismatch
211
+
212
+ await cell.drive.setTypeSchema('woot', testDataSchema_v0)
213
+
214
+ info = {'name': 'win32k.sys', 'type': 'woot'}
215
+ info = await cell.addDriveItem(info, reldir=rootdir)
216
+
217
+ iden = info[-1].get('iden')
218
+
219
+ tick = s_common.now()
220
+ rootuser = cell.auth.rootuser.iden
221
+
222
+ with self.raises(s_exc.SchemaViolation):
223
+ versinfo = {'version': (1, 0, 0), 'updated': tick, 'updater': rootuser}
224
+ await cell.setDriveData(iden, versinfo, {'newp': 'newp'})
225
+
226
+ versinfo = {'version': (1, 1, 0), 'updated': tick + 10, 'updater': rootuser}
227
+ info, versinfo = await cell.setDriveData(iden, versinfo, {'type': 'haha', 'size': 20})
228
+ self.eq(info.get('version'), (1, 1, 0))
229
+ self.eq(versinfo.get('version'), (1, 1, 0))
230
+
231
+ versinfo = {'version': (1, 0, 0), 'updated': tick, 'updater': rootuser}
232
+ info, versinfo = await cell.setDriveData(iden, versinfo, {'type': 'hehe', 'size': 0})
233
+ self.eq(info.get('version'), (1, 1, 0))
234
+ self.eq(versinfo.get('version'), (1, 0, 0))
235
+
236
+ versinfo10, data10 = await cell.getDriveData(iden, vers=(1, 0, 0))
237
+ self.eq(versinfo10.get('updated'), tick)
238
+ self.eq(versinfo10.get('updater'), rootuser)
239
+ self.eq(versinfo10.get('version'), (1, 0, 0))
240
+
241
+ versinfo11, data11 = await cell.getDriveData(iden, vers=(1, 1, 0))
242
+ self.eq(versinfo11.get('updated'), tick + 10)
243
+ self.eq(versinfo11.get('updater'), rootuser)
244
+ self.eq(versinfo11.get('version'), (1, 1, 0))
245
+
246
+ versions = [vers async for vers in cell.getDriveDataVersions(iden)]
247
+ self.len(2, versions)
248
+ self.eq(versions[0], versinfo11)
249
+ self.eq(versions[1], versinfo10)
250
+
251
+ info = await cell.delDriveData(iden, vers=(0, 0, 0))
252
+
253
+ versions = [vers async for vers in cell.getDriveDataVersions(iden)]
254
+ self.len(2, versions)
255
+ self.eq(versions[0], versinfo11)
256
+ self.eq(versions[1], versinfo10)
257
+
258
+ info = await cell.delDriveData(iden, vers=(1, 1, 0))
259
+ self.eq(info.get('updated'), tick)
260
+ self.eq(info.get('version'), (1, 0, 0))
261
+
262
+ info = await cell.delDriveData(iden, vers=(1, 0, 0))
263
+ self.eq(info.get('size'), 0)
264
+ self.eq(info.get('version'), (0, 0, 0))
265
+ self.none(info.get('updated'))
266
+ self.none(info.get('updater'))
267
+
268
+ # repopulate a couple data versions to test migration and delete
269
+ versinfo = {'version': (1, 0, 0), 'updated': tick, 'updater': rootuser}
270
+ info, versinfo = await cell.setDriveData(iden, versinfo, {'type': 'hehe', 'size': 0})
271
+ versinfo = {'version': (1, 1, 0), 'updated': tick + 10, 'updater': rootuser}
272
+ info, versinfo = await cell.setDriveData(iden, versinfo, {'type': 'haha', 'size': 17})
273
+ self.eq(versinfo, (await cell.getDriveData(iden))[0])
274
+
275
+ # This will be done by the cell in a cell storage version migration...
276
+ async def migrate_v1(info, versinfo, data):
277
+ data['woot'] = 'woot'
278
+ return data
279
+
280
+ await cell.drive.setTypeSchema('woot', testDataSchema_v1, migrate_v1)
281
+
282
+ versinfo, data = await cell.getDriveData(iden, vers=(1, 0, 0))
283
+ self.eq('woot', data.get('woot'))
284
+
285
+ versinfo, data = await cell.getDriveData(iden, vers=(1, 1, 0))
286
+ self.eq('woot', data.get('woot'))
287
+
288
+ self.nn(await cell.getDriveInfo(iden))
289
+ self.len(2, [vers async for vers in cell.getDriveDataVersions(iden)])
290
+
291
+ await cell.delDriveData(iden)
292
+ self.len(1, [vers async for vers in cell.getDriveDataVersions(iden)])
293
+
294
+ await cell.delDriveInfo(iden)
295
+
296
+ self.none(await cell.getDriveInfo(iden))
297
+ self.len(0, [vers async for vers in cell.getDriveDataVersions(iden)])
298
+
299
+ with self.raises(s_exc.NoSuchPath):
300
+ await cell.getDrivePath('users/root/win32k.sys')
301
+
302
+ pathinfo = await cell.addDrivePath('foo/bar/baz')
303
+ self.len(3, pathinfo)
304
+ self.eq('foo', pathinfo[0].get('name'))
305
+ self.eq(1, pathinfo[0].get('kids'))
306
+ self.eq('bar', pathinfo[1].get('name'))
307
+ self.eq(1, pathinfo[1].get('kids'))
308
+ self.eq('baz', pathinfo[2].get('name'))
309
+ self.eq(0, pathinfo[2].get('kids'))
310
+
311
+ self.eq(pathinfo, await cell.addDrivePath('foo/bar/baz'))
312
+
313
+ baziden = pathinfo[2].get('iden')
314
+ self.eq(pathinfo, await cell.drive.getItemPath(baziden))
315
+
316
+ info = await cell.setDriveInfoPerm(baziden, {'users': {rootuser: 3}, 'roles': {}})
317
+ self.eq(3, info['perm']['users'][rootuser])
318
+
319
+ with self.raises(s_exc.NoSuchIden):
320
+ # s_drive.rootdir is all 00s... ;)
321
+ await cell.setDriveInfoPerm(s_drive.rootdir, {'users': {}, 'roles': {}})
322
+
323
+ await cell.addDrivePath('hehe/haha')
324
+ pathinfo = await cell.setDriveInfoPath(baziden, 'hehe/haha/hoho')
325
+
326
+ self.eq('hoho', pathinfo[-1].get('name'))
327
+ self.eq(baziden, pathinfo[-1].get('iden'))
328
+
329
+ self.true(await cell.drive.hasPathInfo('hehe/haha/hoho'))
330
+ self.false(await cell.drive.hasPathInfo('foo/bar/baz'))
331
+
332
+ pathinfo = await cell.getDrivePath('foo/bar')
333
+ self.eq(0, pathinfo[-1].get('kids'))
334
+
335
+ pathinfo = await cell.getDrivePath('hehe/haha')
336
+ self.eq(1, pathinfo[-1].get('kids'))
337
+
338
+ with self.raises(s_exc.DupName):
339
+ iden = pathinfo[-2].get('iden')
340
+ name = pathinfo[-1].get('name')
341
+ cell.drive.reqFreeStep(iden, name)
342
+
343
+ walks = [item async for item in cell.drive.walkPathInfo('hehe')]
344
+ self.len(3, walks)
345
+ # confirm walked paths are yielded depth first...
346
+ self.eq('hoho', walks[0].get('name'))
347
+ self.eq('haha', walks[1].get('name'))
348
+ self.eq('hehe', walks[2].get('name'))
349
+
350
+ iden = walks[2].get('iden')
351
+ walks = [item async for item in cell.drive.walkItemInfo(iden)]
352
+ self.len(3, walks)
353
+ self.eq('hoho', walks[0].get('name'))
354
+ self.eq('haha', walks[1].get('name'))
355
+ self.eq('hehe', walks[2].get('name'))
356
+
357
+ self.none(cell.drive.getTypeSchema('newp'))
358
+
359
+ cell.drive.validators.pop('woot')
360
+ self.nn(cell.drive.getTypeValidator('woot'))
361
+
362
+ # move to root dir
363
+ pathinfo = await cell.setDriveInfoPath(baziden, 'zipzop')
364
+ self.len(1, pathinfo)
365
+ self.eq(s_drive.rootdir, pathinfo[-1].get('parent'))
366
+
367
+ pathinfo = await cell.setDriveInfoPath(baziden, 'hehe/haha/hoho')
368
+ self.len(3, pathinfo)
369
+
160
370
  async def test_cell_auth(self):
161
371
 
162
372
  with self.getTestDir() as dirn:
@@ -860,6 +1070,7 @@ class CellTest(s_t_utils.SynTest):
860
1070
  self.nn(slab['xactops'])
861
1071
  self.nn(slab['mapsize'])
862
1072
  self.nn(slab['readonly'])
1073
+ self.nn(slab['readahead'])
863
1074
  self.nn(slab['lockmemory'])
864
1075
  self.nn(slab['recovering'])
865
1076
 
@@ -2914,3 +3125,17 @@ class CellTest(s_t_utils.SynTest):
2914
3125
 
2915
3126
  async with self.getTestCell(s_cell.Cell, dirn=dirn):
2916
3127
  pass
3128
+
3129
+ async def test_cell_initslab_fini(self):
3130
+ class SlabCell(s_cell.Cell):
3131
+ async def initServiceStorage(self):
3132
+ self.long_lived_slab = await self._initSlabFile(os.path.join(self.dirn, 'slabs', 'long.lmdb'))
3133
+ short_slab = await self._initSlabFile(os.path.join(self.dirn, 'slabs', 'short.lmdb'), ephemeral=True)
3134
+ self.short_slab_path = short_slab.lenv.path()
3135
+ await short_slab.fini()
3136
+
3137
+ async with self.getTestCell(SlabCell) as cell:
3138
+ self.true(os.path.isdir(cell.short_slab_path))
3139
+ self.isin(cell.long_lived_slab.fini, cell._fini_funcs)
3140
+ slabs = [s for s in cell.tofini if isinstance(s, s_lmdbslab.Slab) and s.lenv.path() == cell.short_slab_path]
3141
+ self.len(0, slabs)
@@ -41,6 +41,18 @@ def nopickle():
41
41
 
42
42
  class CoroTest(s_t_utils.SynTest):
43
43
 
44
+ async def test_coro_chunks(self):
45
+ async def agen():
46
+ for i in range(101):
47
+ yield i
48
+
49
+ chunks = []
50
+ async for chunk in s_coro.chunks(agen()):
51
+ chunks.append(chunk)
52
+
53
+ self.len(1, chunks[1])
54
+ self.len(100, chunks[0])
55
+
44
56
  async def test_coro_event(self):
45
57
 
46
58
  evnt = s_coro.Event()
@@ -2216,3 +2216,25 @@ class LayerTest(s_t_utils.SynTest):
2216
2216
 
2217
2217
  self.notin('pulls', dst_tree)
2218
2218
  self.notin('pushs', dst_tree)
2219
+
2220
+ async def test_layer_readahead(self):
2221
+
2222
+ async with self.getTestCore() as core:
2223
+
2224
+ layr = core.getLayer()
2225
+ self.true(layr.layrslab.readahead)
2226
+ self.true(layr.layrslab.lenv.flags()['readahead'])
2227
+ self.false(layr.nodeeditslab.readahead)
2228
+ self.false(layr.nodeeditslab.lenv.flags()['readahead'])
2229
+ self.false(layr.dataslab.readahead)
2230
+ self.false(layr.dataslab.lenv.flags()['readahead'])
2231
+
2232
+ with self.setTstEnvars(SYNDEV_CORTEX_LAYER_READAHEAD='false'):
2233
+ iden = await core.callStorm('return($lib.layer.add().iden)')
2234
+ layr = core.getLayer(iden)
2235
+ self.false(layr.layrslab.readahead)
2236
+ self.false(layr.layrslab.lenv.flags()['readahead'])
2237
+ self.false(layr.nodeeditslab.readahead)
2238
+ self.false(layr.nodeeditslab.lenv.flags()['readahead'])
2239
+ self.false(layr.dataslab.readahead)
2240
+ self.false(layr.dataslab.lenv.flags()['readahead'])
@@ -559,3 +559,10 @@ class ModelRevTest(s_tests.SynTest):
559
559
  self.len(2, rnodes)
560
560
 
561
561
  self.eq([node.ndef[0] for node in nodes], [node.ndef[0] for node in reversed(rnodes)])
562
+
563
+ async def test_modelrev_0_2_27(self):
564
+
565
+ async with self.getRegrCore('model-0.2.27') as core:
566
+ nodes = await core.nodes('it:dev:repo:commit:id=" Foo "')
567
+ self.len(1, nodes)
568
+ self.eq('Foo', nodes[0].get('id'))
@@ -243,7 +243,8 @@ class NodeTest(s_t_utils.SynTest):
243
243
  nodepaths = await alist(node.storm(runt, '-> test:int [:loc=$foo]', opts={'vars': {'foo': 'us'}}))
244
244
  self.eq(nodepaths[0][0].props.get('loc'), 'us')
245
245
 
246
- path = nodepaths[0][1].fork(node) # type: s_node.Path
246
+ link = {'type': 'runtime'}
247
+ path = nodepaths[0][1].fork(node, link) # type: s_node.Path
247
248
  path.vars['zed'] = 'ca'
248
249
 
249
250
  # Path present, opts not present
@@ -251,12 +252,18 @@ class NodeTest(s_t_utils.SynTest):
251
252
  self.eq(nodes[0][0].props.get('loc'), 'ca')
252
253
  # path is not updated due to frame scope
253
254
  self.none(path.vars.get('bar'), 'us')
255
+ self.len(2, path.links)
256
+ self.eq({'type': 'prop', 'prop': 'hehe'}, path.links[0][1])
257
+ self.eq(link, path.links[1][1])
254
258
 
255
259
  # Path present, opts present but no opts['vars']
256
260
  nodes = await alist(node.storm(runt, '-> test:int [:loc=$zed] $bar=$foo', opts={}, path=path))
257
261
  self.eq(nodes[0][0].props.get('loc'), 'ca')
258
262
  # path is not updated due to frame scope
259
263
  self.none(path.vars.get('bar'))
264
+ self.len(2, path.links)
265
+ self.eq({'type': 'prop', 'prop': 'hehe'}, path.links[0][1])
266
+ self.eq(link, path.links[1][1])
260
267
 
261
268
  # Path present, opts present with vars
262
269
  nodes = await alist(node.storm(runt, '-> test:int [:loc=$zed] $bar=$baz',
@@ -294,6 +301,10 @@ class NodeTest(s_t_utils.SynTest):
294
301
  self.eq(len(pcln.nodes), len(path.nodes))
295
302
  pcln.nodes.pop(-1)
296
303
  self.ne(len(pcln.nodes), len(path.nodes))
304
+ # Ensure the link elements are independent
305
+ pcln.links.append({'type': 'edge', 'verb': 'seen'})
306
+ self.len(3, pcln.links)
307
+ self.len(2, path.links)
297
308
 
298
309
  # push a frame and clone it - ensure clone mods do not
299
310
  # modify the original path
@@ -3059,12 +3059,29 @@ class StormTest(s_t_utils.SynTest):
3059
3059
  self.len(4, nodes)
3060
3060
 
3061
3061
  q = 'inet:ipv4=1.2.3.4 | tee --join { -> * } { <- * }'
3062
- nodes = await core.nodes(q)
3062
+ msgs = await core.stormlist(q, opts={'links': True})
3063
+ nodes = [m[1] for m in msgs if m[0] == 'node']
3063
3064
  self.len(4, nodes)
3064
- self.eq(nodes[0].ndef, ('inet:asn', 0))
3065
- self.eq(nodes[1].ndef[0], ('inet:dns:a'))
3066
- self.eq(nodes[2].ndef[0], ('edge:refs'))
3067
- self.eq(nodes[3].ndef, ('inet:ipv4', 0x01020304))
3065
+
3066
+ self.eq(nodes[0][0], ('inet:asn', 0))
3067
+ links = nodes[0][1]['links']
3068
+ self.len(1, links)
3069
+ self.eq({'type': 'prop', 'prop': 'asn'}, links[0][1])
3070
+
3071
+ self.eq(nodes[1][0][0], ('inet:dns:a'))
3072
+ links = nodes[1][1]['links']
3073
+ self.len(1, links)
3074
+ self.eq({'type': 'prop', 'prop': 'ipv4', 'reverse': True}, links[0][1])
3075
+
3076
+ self.eq(nodes[2][0][0], ('edge:refs'))
3077
+ links = nodes[2][1]['links']
3078
+ self.len(1, links)
3079
+ self.eq({'type': 'prop', 'prop': 'n2', 'reverse': True}, links[0][1])
3080
+
3081
+ self.eq(nodes[3][0], ('inet:ipv4', 0x01020304))
3082
+ links = nodes[2][1]['links']
3083
+ self.len(1, links)
3084
+ self.eq({'type': 'prop', 'prop': 'n2', 'reverse': True}, links[0][1])
3068
3085
 
3069
3086
  q = 'inet:ipv4=1.2.3.4 | tee --join { -> * } { <- * } { -> edge:refs:n2 :n1 -> * }'
3070
3087
  nodes = await core.nodes(q)
@@ -3834,10 +3851,18 @@ class StormTest(s_t_utils.SynTest):
3834
3851
  self.eq(sorted([n.ndef[1] for n in nodes]), ['test1', 'test2'])
3835
3852
 
3836
3853
  q = '[(test:str=refs) (test:str=foo)] $v=$node.value() | lift.byverb $v'
3837
- nodes = await core.nodes(q)
3854
+ msgs = await core.stormlist(q, opts={'links': True})
3855
+ nodes = [n[1] for n in msgs if n[0] == 'node']
3838
3856
  self.len(4, nodes)
3839
- self.eq({n.ndef[1] for n in nodes},
3857
+ self.eq({n[0][1] for n in nodes},
3840
3858
  {'test1', 'test2', 'refs', 'foo'})
3859
+ links = nodes[1][1]['links']
3860
+ self.len(1, links)
3861
+ self.eq({'type': 'runtime'}, links[0][1])
3862
+
3863
+ links = nodes[2][1]['links']
3864
+ self.len(1, links)
3865
+ self.eq({'type': 'runtime'}, links[0][1])
3841
3866
 
3842
3867
  async def test_storm_nested_root(self):
3843
3868
  async with self.getTestCore() as core: