@entryscape/efix
v1.7.0
Published
A JS-library for setting up fixtures in EntryStore
Keywords
Readme
Entry-Fixture - efix
This library is responsible for starting an EntryStore instance and loading it with contexts and entries based on a directory structure.
The fixture structure
To create a fixture simply create a folder structure that looks like:
fixtures
- basic
- 1.json
- 2.json
- repeatme_2
- car_3.jsonThis structure will create three contexts in the EntryStore instance with contextIds basic, repeatme_1 and repeatme_2. The basic context will have exactly two entries with entryIds 1 and 2 while both the repeatme contexts will have three entries each with entryIds like car_1, car_2 and car_3.
To provide metadata for the context itself, place a file called this.json inside the context folder. It uses the same metadata structure as a regular entry (metadata or metadata_simple) and the metadata is applied to the context entry rather than creating an entry. The this.json file does not result in its own entry.
To make sure each entry is created with metadata it should look like:
{
"link": "http://example.com/ex1",
"metadata": {
"http://example.com/ex1": {
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type": [
{ "value": "http://www.w3.org/ns/dcat#Dataset", "type": "uri" }
],
"http://purl.org/dc/terms/title": [
{ "value": "example 1", "type": "literal" }
]
}
}
}Where the link parameter indicates the resourceURI of a link entry. If no link is provided a local entry will be created where the resourceURI is minted. For instance if the contextId is basic and entryId is 1 the minted resourceURI will be http://127.0.0.1:8282/basic/resource/1.
The metadata structure follows the RDF/JSON format. If a local entry is to be created with this format the resoureURI should be given simply as '_newId', e.g.:
{
"metadata": {
"_newId": {
"http://purl.org/dc/terms/title": [
{ "value": "example 1", "type": "literal" }
]
}
}
}Another alternative is to use a simplified metadata format where the resourceURI is not needed, i.e.:
{
"link": "http://example.com/ex2",
"metadata_simple": {
"rdf:type": "U|dcat:Dataset",
"dcterms:title": "L||example 2"
}
}To provide a literal with a language you write "L|en|some value in english" and to provide a datatype you use "D|xsd:date|2010-10-10". Finally, multiple objects with the same subject and predicate are provided via an array of strings ["L|en|Table", "L|sv|Bord"].
If you want to create a linkreference entry with both a local metadata and cached external metadata you do the following:
{
"link": "http://example.com/ex4",
"metadata_link": "http://example.com/metadata/ex4",
"metadata_simple": {
"dcterms:title": "L||example 4 local"
},
"cached_metadata_simple": {
"rdf:type": "U|dcat:Dataset",
"dcterms:title": "L||example 4 cached"
}
}Note that the example above used the simplified format for metadata, it is also possible to use the RDF/JSON format by using the key cached_metadata.
Local file-backed entries
To create a local entry whose resource is the content of a local file, place the file in a files subdirectory of the context folder and reference it from the entry via the file attribute. The files/ prefix is implied and should not be repeated in the attribute value. The MIME type is provided via the format attribute — it is never auto-detected from the file extension. For instance, given fixtures/advanced/files/report.csv, the entry fixtures/advanced/1.json would look like:
{
"file": "report.csv",
"format": "text/csv",
"metadata_simple": {
"dcterms:title": "L||example file entry"
}
}The format attribute is optional; if omitted the file is uploaded without a declared format. The resource label (rdfs:label in the entry information) is set to the filename — in a Node environment this is not done automatically by entrystore-js (no Content-Disposition header is sent), so efix sets it explicitly. Metadata is applied just like for any other local entry. File uploads are skipped in dry-run mode.
Pipeline entries
To create a pipeline (an entry with the pipeline graph type), set "graphType": "pipeline" in the entry source and provide the ordered list of transforms via a transforms array. Each transform has a type and an optional args object of string key/value pairs. The transforms are created in the given order. For instance, fixtures/advanced/2.json could look like:
{
"graphType": "pipeline",
"transforms": [
{ "type": "empty" },
{
"type": "check",
"args": { "source": "http://www.haninge.se/psidata" }
},
{
"type": "fetch",
"args": { "source": "https://haninge.entryscape.net/store/7/metadata/dcat?recursive=dcat" }
},
{
"type": "validate",
"args": { "profile": "dcat_ap_se" }
},
{ "type": "merge" }
],
"metadata_simple": {
"dcterms:title": "L||Haninge pipeline"
}
}Metadata is applied as for any other entry. Executing the pipeline is out of scope for efix — only the pipeline definition is created.
Graph and string entries
The graphType attribute also supports the graph and string built-in graph types.
A graph entry has an RDF graph as its resource. Provide it either as explicit RDF/JSON via the graph attribute (the _newId placeholder is replaced by the resource URI, just like for metadata) or via the simplified format with the graph_simple attribute (keyed on the resource URI). For instance:
{
"graphType": "graph",
"graph_simple": {
"rdf:type": "U|dcat:Catalog",
"dcterms:title": "L||Graph resource"
}
}A string entry has a plain string as its resource, provided via the string attribute:
{
"graphType": "string",
"string": "a plain string resource"
}In both cases entry metadata (metadata / metadata_simple) is applied as usual. An unsupported graphType value results in an error. The list, context, user and group graph types are intentionally not supported here (contexts are created from the folder structure and this.json).
Using the efix-start and efix-stop commands in another project
Let us assume you have another project where you need to run some tests against an entrystore instance. To achieve this you need to first add this project as a dependency in package.json:
dependencies: {
"@entryscape/efix": "1.0.0"
...
}Second, you need to provide a fixture folder according to above. You can call the folder anything you want, if nothing is provided as parameter it is assumed to be called fixtures.
To start the efix simply call:
pnpm efix-startTo stop efix simply call:
pnpm efix-stopIf you choose another name for your fixture folder, just provide that as a parameter to the efix-start command. Hence, the commend would then be:
"pretest": "efix-start -f myfixturefolder"Finally, you should probably add entrystore*.log to your .gitignore file as these are automatically created log files from entrystore.
Setting up efix as part of the tests
For the test to work properly you need to run the efix-start command before your test and efix-stop after your test.
Typically this achieved as part of your test command:
"scripts": {
"pretest": "efix-start",
"test": "NODE_OPTIONS='--experimental-vm-modules' jest; JEST_EXIT=$?; npm run efix-stop; exit $TEST_EXIT"
}Note that we cannot use a posttest script as that would not run if the tests fail. (The effect would be that the docker instance with the fixtures would not be stopped and the next time you run the tests it will not be a clean instance.)
Advanced options
Efix supports running entrystores in four different configurations (entrystore baseurl and port exposed on):
- instance 1 (default) -
http://127.0.0.1:8281/on port 8281 - instance 2 -
http://127.0.0.1:8282/on port 8282 - instance 3 -
http://127.0.0.1:8281/store/on port 8283 - instance 4 -
http://127.0.0.1:8282/store/on port 8284
Choosing the instance to run
You simply provide the -i flag to specify which instance, e.g.:
pnpm efix-start -i 3Running multiple instances
You may want to run two separate instances, but make sure they run on separate ports. E.g. instance 1 and 2 fits well together as well as instance 3 and 4:
pnpm efix-start
pnpm efix-start -i 2Adding the store path
If you want to run a webb application, e.g. like EntryScape on top of a fixture you will probably want to serve webbpages, scripts and css on the same port. This is accomplished with using a reverse-proxy in a webb server. This is to make sure you avoid CORS issues AND to avoid conflicting the URIs of entrystore with the webb application (which you may want to have in the root). The efix library solves this by providing the instances 3 and 4 and the configurable port. A suitable configuration for instance 3 is:
# Before the efix-start YOU HAVE TO SET UP:
# 1. the web application for port 8181 (anything NOT under /store)
# 2. set up a reverse proxy from :8181/store to :8283/ where the entrystore is runnn
pnpm efix-start -i 3Writing tests based on efix
To write tests you need to first provide the fixture folder. Second you need to connect to the right EntryStore instance and authenticate. The efix library provides the right config for you:
import { EntryStore } from "@entryscape/entrystore-js";
import { config } from '@entryscape/efix';
const es = new EntryStore(config.repository);
es.getAuth().login(config.user, config.password).then(() => {
// authenticated, make requests against the fixtures.
});Furthermore, it might also be useful to load the fixtures without adding them to an EntryStore instance. This can be done via the dryRun mode:
import { EntryStore } from "@entryscape/entrystore-js";
import { efix, silent } from '@entryscape/efix';
// load the fixtures in dry run with a silent logger.
efix('fixtures', true, silent).then(({fixtures}) => {
// fixtures corresponds to the fixture folder in the following structure:
// {
// "basic1": {
// "http://example.com/ex1": // entry or prototypeentry instance
// }
// }
});