Build Process¶
- TODO: complete this file.
- SBT
- Using GraphDB for development and how to initializing the ‘knora-test-unit’ repository
- Using Fuseki for development
Building and Running¶
Using Fuseki¶
Start the provided Fuseki triplestore:
$ cd KNORA_PROJECT_DIRECTORY/triplestores/fuseki
$ ./fuseki-server
Then in another terminal, load some test data into the triplestore:
$ cd KNORA_PROJECT_DIRECTORY/webapi/scripts
$ ./fuseki-load-test-data.sh
Then go back to the webapi root directory and use SBT to start the API server:
$ cd KNORA_PROJECT_DIRECTORY/webapi
$ sbt
> compile
> re-start
To shut down the Knora API server:
> re-stop
Using GraphDB¶
The archive with the newest supported version of the GraphDB-SE triplestore is provided under
`triplestores/graphdb-se`. Please keep in mind, that GraphDB-SE must be licensed separately by the user, and that
no license file is provided in the repository. GraphDB-SE will not run without a license file.
Unzip graphdb-se-x.x.x-dist.zip to a place of your choosing and run the following, to start graphdb:
$ cd /to/unziped/location
$ ./bin/graphdb -Dgraphdb.license.file=/path/to/GRAPHDB_SE.license
After the GraphDB inside the docker container has started, you can find the GraphDB workbench here: http://localhost:7200
Then in another terminal, load some test data into the triplestore:
$ cd KNORA_PROJECT_DIRECTORY/webapi/scripts
$ ./graphdb-se-local-init-knora-test.sh
Then go back to the webapi root directory and use SBT to start the API server:
$ cd KNORA_PROJECT_DIRECTORY/webapi
$ sbt
> compile
> re-start
To shut down the Knora API server:
> re-stop
Running the automated tests¶
Running Tests with Fuseki¶
Make sure you’ve started Fuseki as shown above. Then at the SBT prompt:
> fuseki:test
Running Tests with GraphDB¶
Make sure GraphDB is running (as described earlier).
Then in another terminal, initialise the repository used for automated testing:
$ cd KNORA_PROJECT_DIRECTORY/webapi/scripts
$ ./graphdb-se-local-init-knora-test-unit.sh
Run the automated tests from sbt:
> graphdb:test
Load Testing on Mac OS X¶
To test the Knora API server with many concurrent connections on Mac OS X, you
will need to adjust some kernel parameters to allow more open connections, to
recycle ephemeral ports more quickly, and to use a wider range of ephemeral
port numbers. The script webapi/scripts/os-x-kernel-test-config.sh will do
this.
Continuous Integration¶
For continuous integration testing, we use Travis-CI. Every commit pushed to the git repository or every pull request, triggers the build. Additionaly, in Github there is a litle checkmark beside every commit, signaling the status of the build (successful, unsucessful, ongoing).
The build that is executed on Travis-CI is defined in .travis.yml situated in the root folder of the project, and
looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | dist: trusty
sudo: required
git:
depth: 1
language: scala
scala:
- 2.12.1
jdk:
- oraclejdk8
cache:
directories:
- $HOME/.ivy2
script:
- cd triplestores/fuseki/ && ./fuseki-server &
- cd webapi/ && sbt test
notifications:
slack:
secure: AJZARDC7P6bwjFwk6gpe+p2ozLj+bH3h83PapfCTL0xi7frHd4y6/jXOs9ac+m7ia5FlnzgBxrf0lmaE+IkqlRzxo5dPNYkDIbMC3nrf48kS+uQjf87X1Pn6bDVBLL56L1xIeaEXAqLLWNZ8m1UQ3ykVHgUbUbimjm43eCMpUiretgOqQgreZuLGVxPDU4KrGYZ93FvT2Nzp1Iagld0KXJ1up/uKlpSZAIpJPhgWYIhSGwj9hYG50iENvtsOX/zTe2hjhKWaPmVxHWo8qNyyHfX/+3ODQhvKu3LQsFXbW8WQ1r86EUDrGWeT6mlCYbjR1Wk/7wEKvGts/7vnTNJ8H2xDG9ADc4zIzIpnz0+gndIXuguxuMZEdm1H9okcDqraa4OV01bobr43RVC4hTZCiEBt7wCd/c+C1lJahAQUQoKsbmp5idKrjUyESJ0ZbU6hgkKeOvEvUqv0msYJGWW/C5BlUlro08AgZ9h6nOfu8jJQ49x9QbSWLjTVDg8CEq3w8FDATGA6FKdDqgmsi/3ROjgdewPgyxE3XZ2UpAbAdMPeuGvFoU91X8gScm6ys6abLy0vdCL3LyqmBu/Vzdg1RzU7oqUqSbR5LSMh8pwAwy26j6Awp+pDEzBtyL59yN6r6wgxmbJ5KT+XJReEH6Ao0C6ay23E8T/3YmI3qbjX8xE=
|
It basically means:
- use the virtual machine based environment (line 1)
- checkout git with a shorter history (lines 2-3)
- add scala libraries (lines 4-6)
- add oracle jdk version 8 (lines 7-8)
- cache some directories between builds to make it faster (line 9-11)
- start fuseki and afterwards start all tests (lines 12-14)
- send notification to our slack channel (lines 15-17)
SBT Build Configuration¶
import sbt._
import sbt.Keys._
import spray.revolver.RevolverPlugin._
import NativePackagerHelper._
connectInput in run := true
// Bring the sbt-aspectj settings into this build
//aspectjSettings
lazy val webapi = (project in file(".")).
configs(
FusekiTest,
FusekiTomcatTest,
GraphDBTest,
GraphDBFreeTest,
SesameTest,
EmbeddedJenaTDBTest,
IntegrationTest
).
settings(webApiCommonSettings: _*).
settings(inConfig(FusekiTest)(
Defaults.testTasks ++ Seq(
fork := true,
javaOptions ++= javaFusekiTestOptions,
testOptions += Tests.Argument("-oDF") // show full stack traces and test case durations
)
): _*).
settings(inConfig(FusekiTomcatTest)(
Defaults.testTasks ++ Seq(
fork := true,
javaOptions ++= javaFusekiTomcatTestOptions,
testOptions += Tests.Argument("-oDF") // show full stack traces and test case durations
)
): _*).
settings(inConfig(GraphDBTest)(
Defaults.testTasks ++ Seq(
fork := true,
javaOptions ++= javaGraphDBTestOptions,
testOptions += Tests.Argument("-oDF") // show full stack traces and test case durations
)
): _*).
settings(inConfig(GraphDBFreeTest)(
Defaults.testTasks ++ Seq(
fork := true,
javaOptions ++= javaGraphDBFreeTestOptions,
testOptions += Tests.Argument("-oDF") // show full stack traces and test case durations
)
): _*).
settings(inConfig(SesameTest)(
Defaults.testTasks ++ Seq(
fork := true,
javaOptions ++= javaSesameTestOptions,
testOptions += Tests.Argument("-oDF") // show full stack traces and test case durations
)
): _*).
settings(inConfig(EmbeddedJenaTDBTest)(
Defaults.testTasks ++ Seq(
fork := true,
javaOptions ++= javaEmbeddedJenaTDBTestOptions,
testOptions += Tests.Argument("-oDF") // show full stack traces and test case durations
)
): _*).
settings(inConfig(IntegrationTest)(
Defaults.itSettings ++ Seq(
fork := true,
javaOptions ++= javaIntegrationTestOptions,
testOptions += Tests.Argument("-oDF") // show full stack traces and test case durations
)
): _*).
settings(
libraryDependencies ++= webApiLibs,
scalacOptions ++= Seq("-feature", "-unchecked", "-deprecation", "-Yresolve-term-conflict:package"),
logLevel := Level.Info,
fork in run := true,
javaOptions in run ++= javaRunOptions,
//javaOptions in run <++= AspectjKeys.weaverOptions in Aspectj,
//javaOptions in Revolver.reStart <++= AspectjKeys.weaverOptions in Aspectj,
mainClass in (Compile, run) := Some("org.knora.webapi.Main"),
fork in Test := true,
javaOptions in Test ++= javaTestOptions,
parallelExecution in Test := false,
// enable publishing the jar produced by `sbt it:package`
publishArtifact in (IntegrationTest, packageBin) := true
).
settings( // enable deployment staging with `sbt stage`
mappings in Universal ++= {
// copy the scripts folder
directory("scripts") ++
// copy configuration files to config directory
contentOf("src/main/resources").toMap.mapValues("config/" + _)
},
// add 'config' directory first in the classpath of the start script,
scriptClasspath := Seq("../config/") ++ scriptClasspath.value,
// add license
licenses := Seq(("GNU AGPL", url("https://www.gnu.org/licenses/agpl-3.0"))),
// need this here, but why?
mainClass in Compile := Some("org.knora.webapi.Main")
).
settings(Revolver.settings: _*).
enablePlugins(SbtTwirl). // Enable the SbtTwirl plugin
enablePlugins(JavaAppPackaging) // Enable the sbt-native-packager plugin
lazy val webApiCommonSettings = Seq(
organization := "org.knora",
name := "webapi",
version := "0.1.0-beta",
ivyScala := ivyScala.value map { _.copy(overrideScalaVersion = true) },
scalaVersion := "2.12.1"
)
lazy val akkaVersion = "2.4.16"
lazy val akkaHttpVersion = "10.0.3"
lazy val webApiLibs = Seq(
// akka
"com.typesafe.akka" %% "akka-actor" % akkaVersion,
"com.typesafe.akka" %% "akka-agent" % akkaVersion,
"com.typesafe.akka" %% "akka-stream" % akkaVersion,
"com.typesafe.akka" %% "akka-slf4j" % akkaVersion,
"com.typesafe.akka" %% "akka-http" % akkaHttpVersion,
"com.typesafe.akka" %% "akka-http-xml" % akkaHttpVersion,
"com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion,
"org.scala-lang.modules" %% "scala-xml" % "1.0.6",
// testing
"org.scalatest" %% "scalatest" % "3.0.0" % "test",
//CORS support
"ch.megard" %% "akka-http-cors" % "0.1.10",
// jena
"org.apache.jena" % "apache-jena-libs" % "3.0.0" exclude("org.slf4j", "slf4j-log4j12"),
"org.apache.jena" % "jena-text" % "3.0.0" exclude("org.slf4j", "slf4j-log4j12"),
// http client
// "net.databinder.dispatch" %% "dispatch-core" % "0.11.2",
// logging
"com.typesafe.scala-logging" %% "scala-logging" % "3.5.0",
"ch.qos.logback" % "logback-classic" % "1.1.7",
// input validation
"commons-validator" % "commons-validator" % "1.4.1",
// authentication
"org.bouncycastle" % "bcprov-jdk15on" % "1.56",
"org.springframework.security" % "spring-security-core" % "4.2.1.RELEASE",
// caching
"net.sf.ehcache" % "ehcache" % "2.10.0",
// monitoring - disabled for now
//"org.aspectj" % "aspectjweaver" % "1.8.7",
//"org.aspectj" % "aspectjrt" % "1.8.7",
//"io.kamon" %% "kamon-core" % "0.5.2",
//"io.kamon" %% "kamon-spray" % "0.5.2",
//"io.kamon" %% "kamon-statsd" % "0.5.2",
//"io.kamon" %% "kamon-log-reporter" % "0.5.2",
//"io.kamon" %% "kamon-system-metrics" % "0.5.2",
//"io.kamon" %% "kamon-newrelic" % "0.5.2",
// other
//"javax.transaction" % "transaction-api" % "1.1-rev-1",
"org.apache.commons" % "commons-lang3" % "3.4",
"commons-io" % "commons-io" % "2.4",
"commons-beanutils" % "commons-beanutils" % "1.9.2", // not used by us, but need newest version to prevent this problem: http://stackoverflow.com/questions/14402745/duplicate-classes-in-commons-collections-and-commons-beanutils
"org.jodd" % "jodd" % "3.2.6",
"joda-time" % "joda-time" % "2.9.1",
"org.joda" % "joda-convert" % "1.8",
"com.sksamuel.diff" % "diff" % "1.1.11",
"org.xmlunit" % "xmlunit-core" % "2.1.1",
// testing
"com.typesafe.akka" %% "akka-testkit" % akkaVersion % "test, fuseki, fuseki-tomcat, graphdb, tdb, it",
"com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion % "test, fuseki, fuseki-tomcat, graphdb, tdb, it",
"com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion % "test, fuseki, fuseki-tomcat, graphdb, tdb, it",
"org.scalatest" %% "scalatest" % "3.0.0" % "test, fuseki, fuseki-tomcat, graphdb, tdb, it",
"org.eclipse.rdf4j" % "rdf4j-rio-turtle" % "2.0M3",
"org.rogach" %% "scallop" % "2.0.5",
"com.google.gwt" % "gwt-servlet" % "2.8.0",
"net.sf.saxon" % "Saxon-HE" % "9.7.0-14"
)
lazy val javaRunOptions = Seq(
// "-showversion",
"-Xms2048m",
"-Xmx4096m"
// "-verbose:gc",
//"-XX:+UseG1GC",
//"-XX:MaxGCPauseMillis=500"
)
lazy val javaTestOptions = Seq(
// "-showversion",
"-Xms2048m",
"-Xmx4096m"
// "-verbose:gc",
//"-XX:+UseG1GC",
//"-XX:MaxGCPauseMillis=500",
//"-XX:MaxMetaspaceSize=4096m"
)
lazy val FusekiTest = config("fuseki") extend(Test)
lazy val javaFusekiTestOptions = Seq(
"-Dconfig.resource=fuseki.conf"
) ++ javaTestOptions
lazy val FusekiTomcatTest = config("fuseki-tomcat") extend(Test)
lazy val javaFusekiTomcatTestOptions = Seq(
"-Dconfig.resource=fuseki-tomcat.conf"
) ++ javaTestOptions
lazy val GraphDBTest = config("graphdb") extend(Test)
lazy val javaGraphDBTestOptions = Seq(
"-Dconfig.resource=graphdb.conf"
) ++ javaTestOptions
lazy val GraphDBFreeTest = config("graphdb-free") extend(Test)
lazy val javaGraphDBFreeTestOptions = Seq(
"-Dconfig.resource=graphdb-free.conf"
) ++ javaTestOptions
lazy val SesameTest = config("sesame") extend(Test)
lazy val javaSesameTestOptions = Seq(
"-Dconfig.resource=sesame.conf"
) ++ javaTestOptions
lazy val EmbeddedJenaTDBTest = config("tdb") extend(Test)
lazy val javaEmbeddedJenaTDBTestOptions = Seq(
"-Dconfig.resource=jenatdb.conf"
) ++ javaTestOptions
// The 'IntegrationTest' config does not need to be created here, as it is a built-in config!
// The standard testing tasks are available, but must be prefixed with 'it:', e.g., 'it:test'
// The test need to be stored in the 'it' (and not 'test') folder. The standard source hierarchy is used, e.g., 'src/it/scala'
lazy val javaIntegrationTestOptions = Seq(
"-Dconfig.resource=graphdb.conf"
) ++ javaTestOptions
Webapi Server Startup-Flags¶
The Webapi-Server can be started with a number of flags. These flags can be supplied either to the reStart or the
run command in sbt, e.g.,:
$ sbt
> reStart flag
or
$sbt
> run flag
loadDemoData - Flag¶
When the webapi-server is started with the loadDemoData flag, then at startup, the data which is configured in
application.conf under the app.triplestore.rdf-data key is loaded into the triplestore, and any data in the
triplestore is removed beforehand.
Usage:
$ sbt
> reStart loadDemoData
allowResetTriplestoreContentOperationOverHTTP - Flag¶
When the webapi.server is started with the allowResetTriplestoreContentOperationOverHTTP flag, then the
v1/store/ResetTriplestoreContent route is activated. This route accepts a POST request, with a json payload
consisting of the following exemplary content:
[
{
"path": "../knora-ontologies/knora-base.ttl",
"name": "http://www.knora.org/ontology/knora-base"
},
{
"path": "../knora-ontologies/knora-dc.ttl",
"name": "http://www.knora.org/ontology/dc"
},
{
"path": "../knora-ontologies/salsah-gui.ttl",
"name": "http://www.knora.org/ontology/salsah-gui"
},
{
"path": "_test_data/ontologies/incunabula-onto.ttl",
"name": "http://www.knora.org/ontology/incunabula"
},
{
"path": "_test_data/all_data/incunabula-data.ttl",
"name": "http://www.knora.org/data/incunabula"
}
]
This content corresponds to the payload sent with the ResetTriplestoreContent message, defined inside the
org.knora.webapi.messages.v1.store.triplestoremessages package. The path being the relative path to the ttl
file which will be loaded into a named graph by the name of name.
Usage:
$ sbt
> reStart allowResetTriplestoreContentOperationOverHTTP