Allow basic auth against remote endpoint.
1 parent 888cbb7 commit e4c1dab6724bd85e7dbd88fd2a09a8503e0eb700
@Alex Tucker Alex Tucker authored on 7 Jun 2018
Showing 2 changed files
View
2
■■■
build.sbt
 
version := "1.2"
 
scalaVersion := "2.12.4"
 
// scalacOptions += "-target:jvm-1.7"
 
libraryDependencies ++= Seq(
"org.apache.jena" % "jena-arq" % "3.6.0",
"org.apache.jena" % "jena-cmds" % "3.6.0",
View
103
src/main/scala/uk/org/floop/sparqlTestRunner/Run.scala
import java.net.URI
import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Path}
 
import org.apache.jena.query.{DatasetFactory, QueryExecutionFactory, QueryFactory, ResultSetFormatter}
import org.apache.jena.rdf.model.{Model, ModelFactory}
import org.apache.http.auth.{AuthScope, UsernamePasswordCredentials}
import org.apache.http.client.protocol.HttpClientContext
import org.apache.http.client.utils.URIUtils
import org.apache.http.impl.auth.BasicScheme
import org.apache.http.impl.client.{BasicAuthCache, BasicCredentialsProvider, HttpClients}
import org.apache.jena.query._
import org.apache.jena.rdf.model.ModelFactory
import org.apache.jena.riot.RDFDataMgr
 
import scala.io.Source
import scala.xml.{NodeSeq, PrettyPrinter}
 
case class Config(dir: File = new File("tests/sparql"),
report: File = new File("reports/TESTS-sparql-test-runner.xml"),
ignoreFail: Boolean = false, endpoint: Option[URI] = None,
ignoreFail: Boolean = false, endpoint: Option[URI] = None, auth: Option[String] = None,
data: Seq[File] = Seq())
 
object Run extends App {
val packageVersion: String = getClass.getPackage.getImplementationVersion()
val packageVersion: String = getClass.getPackage.getImplementationVersion
val parser = new scopt.OptionParser[Config]("sparql-testrunner") {
head("sparql-testrunner", packageVersion)
opt[File]('t', "testdir") optional() valueName "<dir>" action { (x, c) =>
c.copy(dir = x)
} text "exit with success even if there are reported failures"
opt[URI]('s', name= "service") optional() valueName "<HTTP URI>" action { (x, c) =>
c.copy(endpoint = Some(x))
} text "SPARQL endpoint to run the queries against"
opt[String]('a', "auth") optional() valueName "<user:pass>" action { (x, c) =>
c.copy(auth = Some(x))
} text "basic authentication username:password"
arg[File]("<file>...") unbounded() optional() action { (x, c) =>
c.copy(data = c.data :+ x) } text "data to run the queries against"
checkConfig( c =>
if (c.endpoint.isDefined && !c.data.isEmpty) {
if (!c.dir.exists || !c.dir.isDirectory) {
failure("Tests directory (" + c.dir.toString + ") doesn't exist or isn't a directory.")
} else if (c.endpoint.isDefined && c.data.nonEmpty) {
failure("Specify either a SPARQL endpoint or data files, not both.")
} else if (c.endpoint.isEmpty && c.data.isEmpty) {
failure("Must specify either a SPARQL endpoint or some data files.")
} else success
)
}
parser.parse(args, Config()) match {
case Some(config) =>
val data = config.endpoint match {
case Some(uri) => Right(uri)
val queryExecution: Query => QueryExecution = config.endpoint match {
case Some(uri) =>
// Querying a remote endpoint; if authentication is required, need to set up pre-emptive auth,
// see https://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html
config.auth match {
case Some(userpass) =>
val target = URIUtils.extractHost(uri) // new HttpHost(uri.getHost, uri.getPort)
val credsProvider = new BasicCredentialsProvider()
credsProvider.setCredentials(
new AuthScope(target.getHostName, target.getPort),
new UsernamePasswordCredentials(userpass))
val authCache = new BasicAuthCache()
authCache.put(target, new BasicScheme())
val context = HttpClientContext.create()
context.setCredentialsProvider(credsProvider)
context.setAuthCache(authCache)
val client = HttpClients.custom.build()
(query: Query) => QueryExecutionFactory.sparqlService(uri.toString, query, client, context)
case None =>
(query: Query) => QueryExecutionFactory.sparqlService(uri.toString, query)
}
case None =>
val dataset = DatasetFactory.create
for (d <- config.data) {
RDFDataMgr.read(dataset, d.toString)
val union = ModelFactory.createDefaultModel
union.add(dataset.getDefaultModel)
union.add(dataset.getUnionModel)
dataset.close()
Left(union)
(query: Query) => QueryExecutionFactory.create(query, union)
}
val (error, results) = runTestsUnder(config.dir, data, config.dir.toPath)
val (error, results) = runTestsUnder(config.dir, queryExecution, config.dir.toPath)
for (dir <- Option(config.report.getParentFile)) {
dir.mkdirs
}
val pp = new PrettyPrinter(80, 2)
val pw = new PrintWriter(config.report)
pw.write(pp.format(<testsuites>{results}</testsuites>))
pw.close
System.exit((error && !config.ignoreFail) match {
case true => 1
case false => 0
})
pw.close()
System.exit(if (error && !config.ignoreFail) 1 else 0)
case None =>
}
 
def runTestsUnder(dir: File, data: Either[Model, URI], root: Path): (Boolean, NodeSeq) = {
def runTestsUnder(dir: File, queryExecution: Query => QueryExecution, root: Path): (Boolean, NodeSeq) = {
var testSuites = NodeSeq.Empty
var testCases = NodeSeq.Empty
var overallError = false
var errors = 0
var subSuiteTimes = 0L
for (f <- dir.listFiles) yield {
if (f.isDirectory) {
val subSuiteStart = System.currentTimeMillis()
val (error, subSuites) = runTestsUnder(f, data, root)
val (error, subSuites) = runTestsUnder(f, queryExecution, root)
testSuites ++= subSuites
overallError |= error
subSuiteTimes += (System.currentTimeMillis() - subSuiteStart)
} else if (f.isFile && f.getName.endsWith(".sparql")) {
className
}
tests += 1
val query = QueryFactory.create(new String(Files.readAllBytes(f.toPath), StandardCharsets.UTF_8))
val exec = data match {
case Left(model) => QueryExecutionFactory.create(query, model)
case Right(uri) => QueryExecutionFactory.sparqlService(uri.toString, query)
}
val exec = queryExecution(query)
if (query.isSelectType) {
var results = exec.execSelect()
var nonEmptyResults = results.hasNext()
val nonEmptyResults = results.hasNext
val timeTaken = (System.currentTimeMillis() - timeTestStart).toFloat / 1000
testCases = testCases ++ <testcase name={comment} class={className} time={timeTaken.toString}>
{
val out = new ByteArrayOutputStream
if (expect.exists && expect.isFile) {
val expectedResults = new String(Files.readAllBytes(expect.toPath), StandardCharsets.UTF_8)
if (actualResults != expectedResults) {
errors += 1
System.err.println(s"Testcase $comment\nExpected:\n${expectedResults}\nActual:\n${actualResults}")
System.err.println(s"Testcase $comment\nExpected:\n$expectedResults\nActual:\n$actualResults")
<error message={"Expected: \n" + expectedResults + "\nGot: \n" + actualResults}/>
}
} else {
// assume there should be no results
if (nonEmptyResults) {
errors += 1
System.err.println(s"Testcase $comment\nExpected empty result set, got:\n${actualResults}")
<failure message={s"Expected empty result set, got:\n${actualResults}"}/>
System.err.println(s"Testcase $comment\nExpected empty result set, got:\n$actualResults")
<failure message={s"Expected empty result set, got:\n$actualResults"}/>
}
}
}
</testcase>