Fix multi-database entity resolution capture validation
This commit is contained in:
1 parent
9c9d9d70d6
commit
a9b49bbb13
2 files changed
+43
-2
No files matched your search
@@ -436,8 +436,16 @@ class EntityResolver:
|
||||
captures=[]
|
||||
for s,ref in zip(plan['searches'],search['capture_refs'],strict=True):
|
||||
c=read_json(reader,ref,'project-capture',self.owner.limits.max_context_bytes)
|
||||
if (ref != self.base(context)+'/captures/'+hashlib.sha256(reader.read_bytes(ref)).hexdigest()+'.json' or c['origin'] != initial['binding']
|
||||
or c['query'] != query_for(s,initial['policy'])):
|
||||
query=query_for(s,initial['policy'])
|
||||
# Reconstruct the query-specific origin from the frozen binding, so
|
||||
# completed cases remain verifiable without a live database provider.
|
||||
binding=copy.deepcopy(initial['binding'])
|
||||
if binding.get('kind') == 'mariadb' and (binding.get('additional_databases') or '.' in query['table']):
|
||||
parts=query['table'].split('.')
|
||||
database,table=(binding['database'],parts[0]) if len(parts)==1 else parts
|
||||
binding.update(selected_database=database,selected_table=table)
|
||||
if (ref != self.base(context)+'/captures/'+hashlib.sha256(reader.read_bytes(ref)).hexdigest()+'.json' or c['origin'] != binding
|
||||
or c['query'] != query):
|
||||
raise InterpretationError('ENTITY_RESOLUTION_CAPTURE_CHANGED')
|
||||
captures.append(c)
|
||||
if search['candidates'] != candidates_for(plan,captures,initial['policy']):
|
||||
|
||||
@@ -126,6 +126,39 @@ def context_of(store):
|
||||
return build_context(json.loads(reader.read_bytes(ref)),ref,InterpretationLimits())
|
||||
|
||||
|
||||
@pytest.mark.parametrize('qualified', [False, True])
|
||||
@pytest.mark.parametrize('wrong_origin', [False, True])
|
||||
def test_multidatabase_capture_origin_and_portable_replay(built_case, tmp_path, qualified, wrong_origin):
|
||||
class MultiDatabase(Database):
|
||||
def binding(self):
|
||||
return {'kind':'mariadb', 'database':'world', 'snapshot_id':self.snapshot,
|
||||
'tables':['components'], 'additional_databases':{'characters':['components']}}
|
||||
|
||||
def binding_for(self, query):
|
||||
database, table = query['table'].split('.') if '.' in query['table'] else ('world', query['table'])
|
||||
return {**self.binding(), 'selected_database':'wrong' if wrong_origin else database,
|
||||
'selected_table':table}
|
||||
|
||||
def validate(self, query):
|
||||
assert query['table'] in {'components','characters.components'}
|
||||
|
||||
store=built_case[0]
|
||||
model=Model(); service=service_for(store,MultiDatabase())
|
||||
if qualified:
|
||||
service.entity_resolution['catalogs'][0]['table']='characters.components'
|
||||
if wrong_origin:
|
||||
with pytest.raises(InterpretationError, match='ENTITY_RESOLUTION_CAPTURE_CHANGED'):
|
||||
run(store,model,service)
|
||||
return
|
||||
result=run(store,model,service)
|
||||
assert result.status=='COMPLETED'
|
||||
assert PackageValidator().validate(result.package).valid
|
||||
receiving=CheckpointStore(type(store.workspace)(tmp_path/'portable-multidb'))
|
||||
receiving.intake(result.package)
|
||||
again=run(receiving,model)
|
||||
assert again.reused and len(model.requests)==3
|
||||
|
||||
|
||||
def test_resolves_unrecorded_subject_preserves_case_and_portable_replay(built_case, tmp_path):
|
||||
store, _, built, _, _ = built_case
|
||||
with PackageReader(built.package) as reader:
|
||||
|
||||
Reference in new issue
Block a user