def testQueryAnnotationsWithMissingGraph(self): """ This test is included to ensure that queries still work as expected when the manifest contains a reference to a non-existent manifest graph """ rodir = self.createTestRo(testbase, "data/ro-test-1", "Test query annotations", "ro-testRoAnnotate") romd = ro_metadata.ro_metadata(ro_config, rodir) roresource = "subdir1/subdir1-file.txt" # Add anotations for file romd.addSimpleAnnotation(roresource, "type", "Test file") romd.addSimpleAnnotation(roresource, "description", "File in test research object") romd.addSimpleAnnotation(roresource, "note", "Research object file created for annotation testing") romd.addSimpleAnnotation(roresource, "title", "Test file in RO") romd.addSimpleAnnotation(roresource, "created", "2011-12-07") romd.addSimpleAnnotation(roresource, "rdf:type", ROTERMS.resource) # Apply non-exietent graph annotation annotation_graph_filename = os.path.join(os.path.abspath(rodir), "annotate-none.rdf") romd.addGraphAnnotation(roresource, annotation_graph_filename) # Query the file anotations query = (make_sparql_prefixes() + """ ASK { ?ro rdf:type ro:ResearchObject ; dcterms:creator "Test User" . ?file rdf:type roterms:resource ; dcterms:type "Test file" ; dcterms:created "2011-12-07" . } """) resp = romd.queryAnnotations(query) self.assertTrue(resp, "Expected 'True' result for query: %s") self.deleteTestRo(rodir) return
def testEvaluateMissingRDF(self): # repeat previous test case, but with RDF output self.setupConfig() rodir = self.createTestRo(testbase, "test-simple-wf", "RO test minim", "ro-testMinim") self.populateTestRo(testbase, rodir) self.annotateWfRo(testbase, rodir) rometa = ro_metadata(ro_config, rodir) minimuri = rometa.getComponentUri("simple-wf-minim.rdf") # Evaluate args = [ "ro", "evaluate", "checklist" , "-a" , "-d", rodir+"/" , "-o", "rdfxml" , "simple-wf-minim.rdf" , "Missing" , "." ] self.outstr.seek(0) with StdoutContext.SwitchStdout(self.outstr): status = ro.runCommand( os.path.join(testbase, TestConfig.ro_test_config.CONFIGDIR), os.path.join(testbase, TestConfig.ro_test_config.ROBASEDIR), args) outtxt = self.outstr.getvalue() assert status == 0, "Status %d, outtxt: %s"%(status,outtxt) # log.debug("status %d, outtxt: \n--------\n%s----"%(status, outtxt)) # Check response returned self.outstr.seek(0) outgraph = rdflib.Graph() outgraph.parse(self.outstr) prefixes = make_sparql_prefixes() rouri = rometa.getRoUri() modeluri = rometa.getComponentUriAbs("simple-wf-minim.rdf#missing_RO_model") log.debug("------ outgraph:\n%s\n----"%(outgraph.serialize(format='turtle'))) probequeries = ( [ "ASK { _:r minim:testedRO <%s> ; minim:minimUri <%s> }"% (rouri, minimuri) , "ASK { _:r minim:testedRO <%s> ; minim:testedModel <%s> }"% (rouri, modeluri) , """ASK { _:r minim:testedRO <%(rouri)s> ; minim:testedPurpose "Missing" ; minim:missingMust [ minim:tryMessage "No workflow present with hens tooth" ; result:binding [ result:variable "_count" ; result:value 0 ] ] }"""% { 'rouri': rouri } , '''ASK { _:r minim:testedRO <%s> ; minim:missingMust [ minim:tryMessage "%s" ] }'''% (rouri, "No workflow present with hens tooth") , '''ASK { _:r minim:testedRO <%s> ; minim:testedTarget <%s> }'''% (rouri, rouri) , '''ASK { <%s> rdfs:label "%s" }'''% (rouri, rdflib.Literal("RO test minim")) ]) for q in probequeries: r = outgraph.query(prefixes+q) self.assertEqual(r.type, 'ASK', "Result type %s for: %s"%(r.type, q)) self.assertTrue(r.askAnswer, "Failed query: %s"%(q)) self.deleteTestRo(rodir) return
def testEvaluateWfInputsRDF(self): # repeat previous test case, but with RDF output self.setupConfig() rodir = self.createTestRo(testbase, "test-simple-wf", "RO test minim", "ro-testMinim") self.populateTestRo(testbase, rodir) self.annotateWfRo(testbase, rodir) rometa = ro_metadata(ro_config, rodir) minimuri = rometa.getComponentUri("simple-wf-minim.rdf") # Evaluate args = [ "ro", "evaluate", "checklist" , "-a" , "-d", rodir+"/" , "-o", "rdfxml" , "simple-wf-minim.rdf" , "Runnable" , "." ] self.outstr.seek(0) with StdoutContext.SwitchStdout(self.outstr): status = ro.runCommand( os.path.join(testbase, TestConfig.ro_test_config.CONFIGDIR), os.path.join(testbase, TestConfig.ro_test_config.ROBASEDIR), args) outtxt = self.outstr.getvalue() assert status == 0, "Status %d, outtxt: %s"%(status,outtxt) log.debug("status %d, outtxt: \n--------\n%s----"%(status, outtxt)) # Check response returned self.outstr.seek(0) outgraph = rdflib.Graph() outgraph.parse(self.outstr) prefixes = make_sparql_prefixes() rouri = rometa.getRoUri() modeluri = rometa.getComponentUriAbs("simple-wf-minim.rdf#runnable_RO_model") probequeries = ( [ '''ASK { _:r minim:testedRO <%s> ; minim:minimUri <%s> }'''% (rouri, minimuri) , '''ASK { _:r minim:testedRO <%s> ; minim:testedModel <%s> }'''% (rouri, modeluri) , '''ASK { _:r minim:testedRO <%s> ; minim:satisfied [ minim:tryMessage "%s" ] }'''% (rouri, "Workflow instance or template found") , '''ASK { _:r minim:testedRO <%s> ; minim:satisfied [ minim:tryMessage "%s" ] }'''% (rouri, "All workflow inputs referenced or present") , '''ASK { _:r minim:testedRO <%s> ; minim:fullySatisfies <%s> }'''% (rouri, modeluri) , '''ASK { _:r minim:testedRO <%s> ; minim:nominallySatisfies <%s> }'''% (rouri, modeluri) , '''ASK { _:r minim:testedRO <%s> ; minim:minimallySatisfies <%s> }'''% (rouri, modeluri) , '''ASK { <%s> rdfs:label "%s" }'''% (rouri, rdflib.Literal("RO test minim")) ]) for q in probequeries: log.debug("- query %s"%(q)) r = outgraph.query(prefixes+q) self.assertEqual(r.type, 'ASK', "Result type %s for: %s"%(r.type, q)) self.assertTrue(r.askAnswer, "Failed query: %s"%(q)) self.deleteTestRo(rodir) return
def testQueryAnnotations(self): rodir = self.createTestRo(testbase, "data/ro-test-1", "Test query annotations", "ro-testRoAnnotate") romd = ro_metadata.ro_metadata(ro_config, rodir) roresource = "subdir1/subdir1-file.txt" # Add anotations for file romd.addSimpleAnnotation(roresource, "type", "Test file") romd.addSimpleAnnotation(roresource, "description", "File in test research object") romd.addSimpleAnnotation(roresource, "note", "Research object file created for annotation testing") romd.addSimpleAnnotation(roresource, "title", "Test file in RO") romd.addSimpleAnnotation(roresource, "created", "2011-12-07") romd.addSimpleAnnotation(roresource, "rdf:type", ROTERMS.resource) # Query the file anotations queryprefixes = make_sparql_prefixes() query = (queryprefixes + """ ASK { ?ro rdf:type ro:ResearchObject ; dcterms:creator "Test User" . ?file rdf:type roterms:resource ; dcterms:type "Test file" ; dcterms:created "2011-12-07" . } """) resp = romd.queryAnnotations(query) self.assertTrue(resp, "Expected 'True' result for query: %s"%(query)) query = (queryprefixes + """ ASK { ?ro rdf:type ro:ResearchObject ; dcterms:creator "Not user" . } """) resp = romd.queryAnnotations(query) self.assertFalse(resp, "Expected 'False' result for query: %s"%(query)) query = (queryprefixes + """ SELECT * WHERE { ?ro rdf:type ro:ResearchObject ; dcterms:creator "Test User" . ?file rdf:type roterms:resource ; dcterms:type "Test file" ; dcterms:created ?date . } """) rouri = romd.getRoUri() resourceuri = romd.getComponentUri(roresource) resp = romd.queryAnnotations(query) self.assertEqual(resp[0]['ro'], rouri) self.assertEqual(resp[0]['file'], romd.getComponentUri(roresource)) self.assertEqual(resp[0]['date'], rdflib.Literal("2011-12-07")) self.deleteTestRo(rodir) return
def testQueryAnnotations(self): (status, reason, rouri, manifest) = self.createTestRO("testQueryAnnotations") self.assertEqual(status, 201) romd = ro_metadata.ro_metadata(ro_config, rouri) resuri = romd.getComponentUriAbs(Config.TEST_RESOURCE) resref = Config.TEST_RESOURCE (status, reason, bodyuri, agraph) = self.createTestAnnotation(rouri, resuri, resref) self.assertEqual(status, 201) # Query the file anotations queryprefixes = make_sparql_prefixes() query = (queryprefixes + """ ASK { ?ro rdf:type ro:ResearchObject ; dcterms:creator ?user . } """) resp = romd.queryAnnotations(query) self.assertTrue(resp, "Expected 'True' result for query: %s"%(query)) query = (queryprefixes + """ ASK { <%(resuri)s> dcterms:title ?title . } """%{"resuri": str(resuri)}) resp = romd.queryAnnotations(query) self.assertTrue(resp, "Expected 'True' result for query: %s"%(query)) query = (queryprefixes + """ ASK { ?ro rdf:type ro:ResearchObject ; dcterms:creator "Not user" . } """) resp = romd.queryAnnotations(query) self.assertFalse(resp, "Expected 'False' result for query: %s"%(query)) query = (queryprefixes + """ SELECT * WHERE { ?ro rdf:type ro:ResearchObject ; ore:aggregates ?file . ?file dcterms:title ?title . } """) rouri = romd.getRoUri() resp = romd.queryAnnotations(query) self.assertEqual(resp[0]['ro'], rouri) self.assertEqual(resp[0]['file'], resuri) self.assertEqual(resp[0]['title'], rdflib.Literal("Title for %s"%(Config.TEST_RESOURCE))) return
def testEvaluateRDF(self): self.setupConfig() rodir = self.createTestRo(testbase, "test-chembox", "RO test minim", "ro-testMinim") rouri = ro_manifest.getRoUri(rodir) self.populateTestRo(testbase, rodir) rometa = ro_metadata(ro_config, rodir) resuri = rometa.getComponentUriAbs("http://purl.org/net/chembox/Ethane") reslabel = "Ethane" rometa.addGraphAnnotation(resuri, "Ethane.ttl") # Now run evaluation against test RO (minimgr, evalresult) = ro_eval_minim.evaluate(rometa, "Minim-chembox.ttl", # Minim file resuri, # Target resource "complete") # Purpose resultgr = ro_eval_minim.evalResultGraph(minimgr, evalresult) log.debug("------ resultgr:\n%s\n----"%(resultgr.serialize(format='turtle'))) # pretty-xml ## print "------ resultgr:\n%s\n----"%(resultgr.serialize(format='turtle')) # Check response returned modeluri = rdflib.URIRef('http://example.com/chembox-samples/minim_model') prefixes = make_sparql_prefixes() probequeries = ( [ '''ASK { _:r minim:testedRO <%s> ; minim:minimUri <%s> }'''% (rouri, rometa.getComponentUri("Minim-chembox.ttl")) , '''ASK { _:r minim:testedRO <%s> ; minim:testedModel <%s> }'''% (rouri, modeluri) , '''ASK { _:r minim:testedTarget <%s> ; minim:satisfied [ minim:tryMessage "%s" ] }'''% (resuri, "InChI identifier is present") , '''ASK { _:r minim:testedTarget <%s> ; minim:satisfied [ minim:tryMessage "%s" ] }'''% (resuri, "ChemSpider identifier is present") , '''ASK { _:r minim:testedTarget <%s> ; minim:missingMay [ minim:tryMessage "%s" ] }'''% (resuri, "No synomym is present") , '''ASK { _:r minim:testedTarget <%s> ; minim:nominallySatisfies <%s> }'''% (resuri, modeluri) , '''ASK { _:r minim:testedTarget <%s> ; minim:minimallySatisfies <%s> }'''% (resuri, modeluri) , '''ASK { <%s> rdfs:label "%s" }'''% (resuri, reslabel) ]) for q in probequeries: r = resultgr.query(prefixes+q) self.assertEqual(r.type, 'ASK', "Result type %s for: %s"%(r.type, q)) self.assertTrue(r.askAnswer, "Failed query: %s"%(q)) self.deleteTestRo(rodir) return
def testQueryAnnotationsRemote(self): romd = ro_metadata.ro_metadata( ro_config, "http://andros.zoo.ox.ac.uk/workspace/wf4ever-ro-catalogue/v0.1/simple-requirements/" ) # Query the file anotations queryprefixes = make_sparql_prefixes() query = (queryprefixes + """ ASK { ?ro rdf:type ro:ResearchObject ; dcterms:creator "Test user" ; ore:aggregates ?file . } """) resp = romd.queryAnnotations(query) self.assertTrue(resp, "Expected 'True' result for query: %s") query = (queryprefixes + """ ASK { ?ro rdf:type ro:ResearchObject ; dcterms:creator "Not user" . } """) resp = romd.queryAnnotations(query) self.assertFalse(resp, "Expected 'False' result for query: %s") query = (queryprefixes + """ SELECT * WHERE { ?ro rdf:type ro:ResearchObject ; dcterms:creator "Test user" ; ore:aggregates ?file . } """) rouri = romd.getRoUri() resourceuri = romd.getComponentUri("README") resp = romd.queryAnnotations(query) self.assertEqual(resp[0]['ro'], rouri) aggs = [ respn['file'] for respn in resp ] self.assertIn( resourceuri, aggs, repr(aggs)) return
def doQuery(rometa, queryPattern, queryVerb=None, resultMod="", queryPrefixes=None, initBindings=None): # @@TODO - factor out query construction from various places below to use this querytemplate = (make_sparql_prefixes(queryPrefixes or [])+ """ BASE <%(querybase)s> %(queryverb)s { %(querypattern)s } %(resultmod)s """) queryparams = ( { 'querybase': str(rometa.getRoUri()) , 'queryverb': queryVerb or "SELECT * WHERE" , 'querypattern': queryPattern , 'resultmod': resultMod or "" }) query = querytemplate%queryparams log.debug(" - doQuery: "+query) resp = rometa.queryAnnotations(query, initBindings=initBindings) return resp
def evalQueryTest(rometa, rule, constraintbinding): """ rometa ro_metadata for RO to test rule requirement rule to evaluate constraintbinding value bindings generated by constraint matching: 'targetro' and 'targetres', and maybe others Returns (satisfied, binding, msg) """ log.debug("evalQueryTest: rule: \n----\n %s, \n----\nconstraintbinding:\n %s\n----"%(repr(rule), repr(constraintbinding))) querytemplate = (make_sparql_prefixes(rule['prefixes'])+ """ BASE <%(querybase)s> %(queryverb)s { %(querypattern)s } %(resultmod)s """) satisfied = True simplebinding = constraintbinding.copy() if rule['exists'] and not rule['query']: # Bare "exists" is syntactic sugar for "query" with "min=1" rule['query'] = rule['exists'] rule['exists'] = None rule['min'] = rule['min'] or 1 # print >>sys.stderr, "@@@@@@" # print >>sys.stderr, repr(rule) # print >>sys.stderr, "@@@@@@" if rule['query']: count_min = rule['min'] count_max = rule['max'] aggregates = rule['aggregates_t'] islive = rule['islive_t'] exists = rule['exists'] assert (count_min or count_max or aggregates or islive or exists), ( "minim:QueryTestRule requires "+ "minim:min, minim:max, minim:aggregatesTemplate, minim:isLiveTemplate and/or minim:exists value") if aggregates: aggregates = str(aggregates).strip() if islive: islive = str(islive).strip() queryparams = ( { 'querybase': str(rometa.getRoUri()) , 'queryverb': "SELECT DISTINCT * WHERE" , 'querypattern': rule['query'] , 'resultmod': rule['resultmod'] or "" }) query = querytemplate%queryparams log.debug(" - QueryTest: "+query) resp = rometa.queryAnnotations(query, initBindings=constraintbinding) log.debug(" - QueryTest resp: "+repr(resp)) simplebinding['_count'] = len(resp) satisfied_count = 0 total_count = len(resp) result_list = [] failure_message_template = rule['showfail'] or rule['show'] for binding in resp: satisfied = True failmsg = failure_message_template simplebinding = constraintbinding.copy() for k in binding: if not isinstance(k,rdflib.BNode): simplebinding[str(k)] = unicode(binding[k]) simplebinding['_count'] = len(resp) # Do the required test if aggregates: fileref = uritemplate.expand(aggregates, simplebinding) fileuri = rometa.getComponentUri(fileref) simplebinding.update({'_fileref': fileref, '_fileuri': fileuri}) log.debug("evalQueryTest RO aggregates %s (%s)"%(fileref, str(fileuri))) satisfied = rometa.roManifestContains( (rometa.getRoUri(), ORE.aggregates, fileuri) ) failmsg = failmsg or "Aggregates %(_fileref)s" if islive: fileref = uritemplate.expand(islive, simplebinding) fileuri = rometa.getComponentUri(fileref) simplebinding.update({'_fileref': fileref, '_fileuri': fileuri}) log.debug("evalQueryTest RO isLive %s (%s)"%(fileref, str(fileuri))) satisfied = isLiveUri(fileuri) failmsg = failmsg or "Accessible %(_fileref)s" if exists: existsparams = ( { 'querybase': str(rometa.getRoUri()) , 'queryverb': "ASK" , 'querypattern': exists , 'resultmod': "" }) query = querytemplate%existsparams simplebinding.update({'_pattern': exists, '_query': query}) log.debug("evalContentMatch RO test exists: \nquery: %s \nbinding: %s"% (query, repr(binding))) satisfied = rometa.queryAnnotations(query,initBindings=binding) failmsg = failmsg or "Exists %(_fileref)s" # Test done, defines: satisfied, failmsg, simplebinding log.debug("Satisfied: %s"%(repr(satisfied))) if satisfied: satisfied_count += 1 result_list.append((satisfied, failmsg, simplebinding)) # All responses tested else: raise ValueError("Query test rule has no query: %s"%repr(rule)) # Sort out final response log.debug("evalQueryTest RO satisfied_count %d"%(satisfied_count)) if count_min or count_max: satisfied = ( (not count_min or (satisfied_count >= count_min)) and (not count_max or (satisfied_count <= count_max)) ) binding = constraintbinding.copy() binding['_count'] = satisfied_count msg = (rule['showpass'] if satisfied else rule['showfail']) msh = msg or rule['show'] or "Cardinality requirement failed" elif total_count == 0: binding = simplebinding satisfied = False if rule['showmiss'] else True msg = rule['showmiss'] or rule['showpass'] or rule['show'] or "No matches" elif (satisfied_count < total_count): satisfied = False # Pick out first failure (for now): (msg, binding) = ((failmsg,binding) for (satisfied, failmsg, binding) in result_list if not satisfied).next() else: satisfied = True binding = simplebinding # last result tested msg = rule['showpass'] # Add collected values to binding returned addCollectedVariables(rule['list'], [True, False], result_list, binding) addCollectedVariables(rule['listfail'], [False], result_list, binding) addCollectedVariables(rule['listpass'], [True], result_list, binding) return (satisfied, binding, msg)
def evalContentMatch(rometa, rule, constraintbinding): """ rometa ro_metadata for RO to test rule requirement rule to evaluate constraintbinding value bindings generated by constraint matching: 'targetro' and 'targetres' """ log.debug("evalContentMatch: rule: \n %s, \nconstraintbinding:\n %s"%(repr(rule), repr(constraintbinding))) querytemplate = (make_sparql_prefixes()+ """ %(queryverb)s { %(querypattern)s } %(queryorder)s """) satisfied = True simplebinding = constraintbinding.copy() if rule['forall']: log.debug("forall rule: "+repr(rule)) exists = rule['exists'] template = rule['template'] islive = rule['islive'] assert (exists or template or islive), ( "minim:forall construct (%(forall)s) requires "%(rule)+ "minim:aggregatesTemplate, minim:isLiveTemplate and/or minim:exists value"+ "") if template: template = str(template).strip() if islive: islive = str(islive).strip() queryparams = ( { 'queryverb': "SELECT * WHERE" , 'querypattern': rule['forall'] , 'queryorder': rule['orderby'] or "" }) query = querytemplate%queryparams log.debug(" - forall query: "+query) ### @@TODO: Why is this failing? # resp = rometa.queryAnnotations(query, initBindings=constraintbinding) resp = rometa.queryAnnotations(query) log.debug(" - forall resp: "+repr(resp)) simplebinding['_count'] = len(resp) if len(resp) == 0 and rule['showmiss']: satisfied = False for binding in resp: satisfied = False # Extract keys and values from query result to return with result simplebinding = constraintbinding.copy() for k in binding: if not isinstance(k,rdflib.BNode): simplebinding[str(k)] = str(binding[k]) simplebinding['_count'] = len(resp) # @@TODO remove this when rdflib bug resolved if str(k) in ['if', 'of'] and str(binding[k])[:5] not in ["file:","http:"]: # Houston, we have a problem... agraph = rometa.roannotations log.warning( "--------------------" ) log.debug( "Graph: "+agraph.serialize(format="xml") ) log.warning( "Query: "+query ) log.warning( "Response bindings: "+repr(resp) ) log.warning( "--------------------" ) ### assert False, "Aborted" if exists: # existence query against forall results existsparams = ( { 'queryverb': "ASK" , 'querypattern': exists , 'queryorder': "" }) query = querytemplate%existsparams log.debug("evalContentMatch RO test exists: \nquery: %s \nbinding: %s"% (query, repr(binding))) satisfied = rometa.queryAnnotations(query,initBindings=binding) if template: # Construct URI for file from template # Uses code copied from http://code.google.com/p/uri-templates fileref = uritemplate.expand(template, simplebinding) fileuri = rometa.getComponentUri(fileref) # Test if URI is aggregated log.debug("evalContentMatch RO aggregates %s (%s)"%(fileref, str(fileuri))) satisfied = rometa.roManifestContains( (rometa.getRoUri(), ORE.aggregates, fileuri) ) if islive: # Construct URI for file from template # Uses code copied from http://code.google.com/p/uri-templates fileref = uritemplate.expand(islive, simplebinding) fileuri = rometa.getComponentUri(fileref) # Test if URI is live (accessible) log.debug("evalContentMatch RO islive %s (%s)"%(fileref, str(fileuri))) satisfied = isLiveUri(fileuri) log.debug("evalContentMatch (forall) RO satisfied %s"%(satisfied)) if not satisfied: break elif rule['exists']: queryparams = ( { 'queryverb': "ASK" , 'querypattern': rule['exists'] , 'queryorder': "" }) query = querytemplate%queryparams log.debug("- query %s"%(query)) satisfied = rometa.queryAnnotations(query) log.debug("- satisfied %s"%(satisfied)) else: raise ValueError("Unrecognized content match rule: %s"%repr(rule)) return (satisfied,simplebinding)
__author__ = "Graham Klyne ([email protected])" __copyright__ = "Copyright 2011-2013, University of Oxford" __license__ = "MIT (http://opensource.org/licenses/MIT)" import os, os.path import sys import logging import json import rdflib from rocommand.ro_namespaces import RDF, DCTERMS, RO, AO, ORE from rocommand.ro_prefixes import make_sparql_prefixes sparql_prefixes = make_sparql_prefixes() log = logging.getLogger(__name__) def LIT(l): return rdflib.Literal(l) def REF(u): return rdflib.URIRef(u) # Report structure used to get evaluation result URI from result graph # Query idiom adapted from http://lists.w3.org/Archives/Public/public-sparql-dev/2006JulSep/0000.html # # Report a inserts one of the following status URIs: # http://purl.org/minim/minim#fullySatifies # http://purl.org/minim/minim#nominallySatifies # http://purl.org/minim/minim#minimallySatifies # http://purl.org/minim/minim#potentiallySatisfies (actually: did not satisfy) #