Commit 099b64b0 authored by Siebers, Michael's avatar Siebers, Michael
Browse files

Merge branch '23-automate-api-tests' into 'master'

Resolve "Automate API-tests"

Closes #62, #52, #51, and #23

See merge request cogsys/dare2del/demonstrator!22
parents e910aa1c 3146834c
stages:
- test
- build
- validate
- deploy
- unit_test1
- unit_test2
- integration_test
- pre_build
- build
- validate
- deploy
variables:
SWI_VERSION: 8.2.2
SWI_VERSION: 8.2.2
CONTAINER_DEPLOY_IMAGE: "webapi"
SYSTEM_TEST_IMAGE: "testing/system"
FORCE_UNIT_TESTS:
value: "no"
description: >
Change this variable to "yes" to run unit tests whether required or not.
Per default, unit tests run fully for tag commits, run fully for commits
on the default branch, and run for MR pipelines targetting the default
branch if files depended on have changed. If forced, unit tests run for
all MR pipelines if files depended on have changed and run fully for all
commits on branches without MR.
FORCE_INTEGRATION_TESTS:
value: "no"
description: >
Change this variable to "yes" to run integration tests whether required or
not. Per default, integration tests run fully for tag commits, run fully
for commits on the default branch, and run for MR pipelines targetting the
default branch if files depended on have changed. If forced, integration
tests run for all MR pipelines if files depended on have changed and run
fully for all commits on branches without MR.
FORCE_SYSTEM_TESTS:
value: "no"
description: >
Change this variable to "yes" to run system tests whether required or
not. Per default, system tests run for tag commits, commits on the default
branch, and MR pipelines targetting the default branch. If forced, system
tests run for all MR pipelines and all commits on branches without MR.
FORCE_DOCKER_BUILD:
value: "no"
description: >
Change this variable to "yes" to build a docker image for branches other
than the default branch.
# NOTE: Several of job's rules could be simplified or easier to understand by
# using workflow:variables. However, this feature is currently not
# available at our GitLab server.
#
# Assuming all variables are initialized to "no", the following might
# do the trick.
#
# workflow:
# rules:
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
# && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
# variables:
# MERGE_TO_MASTER: "yes"
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
# variables:
# MERGE_TO_OTHER: "yes"
# - if: $CI_COMMIT_TAG
# variables:
# CREATE_TAG: "yes"
# - if: $CI_PIPELINE_SOURCE == "push"
# && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# variables:
# PUSH_TO_MASTER: "yes"
# - if: $CI_PIPELINE_SOURCE == "push"
# && ($CI_OPEN_MERGE_REQUESTS == null || $CI_OPEN_MERGE_REQUESTS == "")
# variables:
# PUSH_TO_OTHER: "yes"
# PUSH_TO_OTHER_WITHOUT_MR: "yes"
# - if: $CI_PIPELINE_SOURCE == "push"
# variables:
# PUSH_TO_OTHER: "yes"
# PUSH_TO_OTHER_WITH_MR: "yes"
#
# Template for Prolog test jobs
.prolog_test:
image: swipl:$SWI_VERSION
stage: test
script:
- swipl -s "tests/${TEST_FILE}" -t "run_all_tests" > "${REPORT_PATH}"
timeout: 15m
artifacts:
paths:
- "$REPORT_PATH"
expire_in: 3 days
image: swipl:$SWI_VERSION
script:
- swipl "tests/plunit/${TEST_FILE}" > "${REPORT_PATH}"
timeout: 15m
artifacts:
paths:
- "$REPORT_PATH"
expire_in: 3 days
test_theory_common:
extends: .prolog_test
variables:
TEST_FILE: irrelevance_common.plt
REPORT_PATH: coverage_irrelevance_common
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || ( $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH )
changes:
- src/version.pl
- irrelevance_common.pl
- tests/irrelevance_common.plt
- tests/test_utils.pl
- tests/data_theory_common.pl
- if: $CI_COMMIT_TAG
- when: never
extends: .prolog_test
stage: unit_test1
variables:
TEST_FILE: irrelevance_common.plt
REPORT_PATH: coverage_irrelevance_common
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& ( $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
|| $FORCE_UNIT_TESTS == "yes" )
changes:
- irrelevance_common.pl
- tests/plunit/irrelevance_common.plt
- tests/plunit/test_utils.pl
- tests/plunit/data_theory_common.pl
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "push"
&& ($CI_OPEN_MERGE_REQUESTS == null || $CI_OPEN_MERGE_REQUESTS == "")
&& $FORCE_UNIT_TESTS == "yes"
test_web_api:
extends: .prolog_test
variables:
TEST_FILE: web_api.plt
REPORT_PATH: coverage_web_api
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || ( $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH )
changes:
- src/version.pl
- src/web_api.pl
- src/web_api/*.pl
- tests/web_api.plt
- tests/test_utils.pl
- tests/web_api/*.plt
- if: $CI_COMMIT_TAG
- when: never
extends: .prolog_test
stage: unit_test2
variables:
TEST_FILE: web_api.plt
REPORT_PATH: coverage_web_api
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& ( $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
|| $FORCE_UNIT_TESTS == "yes" )
changes:
- src/web_api.pl
- src/web_api/*.pl
- tests/plunit/web_api.plt
- tests/plunit/test_utils.pl
- tests/plunit/web_api/*.plt
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "push"
&& ($CI_OPEN_MERGE_REQUESTS == null || $CI_OPEN_MERGE_REQUESTS == "")
&& $FORCE_UNIT_TESTS == "yes"
test_types:
extends: .prolog_test
variables:
TEST_FILE: types.plt
REPORT_PATH: coverage_types
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || ( $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH )
changes:
- src/version.pl
- src/types.pl
- tests/types.plt
- tests/types/*.plt
- tests/test_utils.pl
- if: $CI_COMMIT_TAG
- when: never
extends: .prolog_test
stage: unit_test2
variables:
TEST_FILE: types.plt
REPORT_PATH: coverage_types
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& ( $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
|| $FORCE_UNIT_TESTS == "yes" )
changes:
- src/types.pl
- tests/plunit/types.plt
- tests/plunit/types/*.plt
- tests/plunit/test_utils.pl
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "push"
&& ($CI_OPEN_MERGE_REQUESTS == null || $CI_OPEN_MERGE_REQUESTS == "")
&& $FORCE_UNIT_TESTS == "yes"
needs: []
.test_start_stop:
image: swipl:$SWI_VERSION
stage: integration_test
variables:
START_SCRIPT: undefined
timeout: 5m
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& ( $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
|| $FORCE_INTEGRATION_TESTS == "yes" )
changes:
- $START_SCRIPT
- app_common.pl
- src/**/*.pl
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& $FORCE_INTEGRATION_TESTS == "yes"
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "push"
&& ($CI_OPEN_MERGE_REQUESTS == null || $CI_OPEN_MERGE_REQUESTS == "")
&& $FORCE_INTEGRATION_TESTS == "yes"
test_interactive:start_stop:
extends: .test_start_stop
variables:
START_SCRIPT: run.pl
script:
- swipl -t server_stop $START_SCRIPT
test_daemon:start_stop:
extends: .test_start_stop
variables:
START_SCRIPT: daemon.pl
script:
- swipl $START_SCRIPT --user nobody
- swipl $START_SCRIPT --shutdown
container:build:
stage: build
script:
- "docker build --tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} ."
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" ${CI_REGISTRY}
- "docker push ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}"
tags:
- docker
stage: build
script:
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" ${CI_REGISTRY}
- docker image pull "${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:latest" || true
- docker image pull "${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:$CI_COMMIT_REF_SLUG" || true
- "docker build --tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} ${CACHE_OPTION} ."
- "docker push ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}"
tags:
- docker
rules:
- if: $CI_COMMIT_TAG
variables:
CACHE_OPTION: --no-cache
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == "$CI_DEFAULT_BRANCH"
variables:
CACHE_OPTION: --cache-from "${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:latest"
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH
&& $FORCE_DOCKER_BUILD == "yes"
variables:
CACHE_OPTION: --cache-from "${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:latest" --cache-from "${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:${CI_COMMIT_REF_SLUG}"
container:validate:
stage: validate
image:
name: byrnedo/alpine-curl
entrypoint: ["/bin/sh", "-c"]
services:
- name: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}
alias: tested_container
script:
- curl -fsS --location --output /dev/null --retry 50 --retry-delay 5 --retry-connrefused --retry-max-time 300 "http://tested_container/state"
needs: ["container:build"]
stage: validate
image:
name: postman/newman:5.2.3-alpine
entrypoint: ["/bin/sh", "-c"]
services:
- name: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}
alias: webapi
before_script:
- node --version
- newman --version
script:
- newman run tests/container/up_and_running.json -e tests/container/env.json --reporters junit --reporter-junit-export="container-report.xml" --bail
rules:
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH
&& $FORCE_DOCKER_BUILD == "yes"
needs:
- job: "container:build"
artifacts: false
artifacts:
when: always
reports:
junit: container-report.xml
container:deploy:
......@@ -97,27 +262,42 @@ container:deploy:
script:
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" ${CI_REGISTRY}
- "docker image pull ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}"
- "docker tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} ${CI_REGISTRY_IMAGE}/${DEPLOY_IMAGE}:${DEPLOY_TAG}"
- "docker push ${CI_REGISTRY_IMAGE}/${DEPLOY_IMAGE}:${DEPLOY_TAG}"
- "docker tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} ${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:${DEPLOY_TAG}"
- "docker push ${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:${DEPLOY_TAG}"
- "docker logout ${DEPLOY_REGISTRY}"
variables:
DEPLOY_IMAGE: "webapi"
tags:
- docker
rules:
- if: $CI_COMMIT_TAG
variables:
DEPLOY_TAG: $CI_COMMIT_REF_SLUG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
variables:
DEPLOY_TAG: latest
- if: $CI_COMMIT_BRANCH
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH
&& $FORCE_DOCKER_BUILD == "yes"
variables:
DEPLOY_TAG: $CI_COMMIT_REF_SLUG
- when: never
standalone documentation:
documentation:prepare_container:
stage: pre_build
script:
- "true" # dummy for now
tags:
- docker
rules:
- if: $CI_COMMIT_TAG
variables:
CACHE_OPTION: --no-cache
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
variables:
CACHE_OPTION: --cache-from "${CI_REGISTRY_IMAGE}/${SYSTEM_TEST_IMAGE}:${CI_COMMIT_REF_SLUG}"
documentation:build:
stage: build
image: swipl:$SWI_VERSION
variables:
......@@ -129,18 +309,182 @@ standalone documentation:
- pip3 install lxml
- utils/generate_documentation.sh "$BUILD_DIR" "webapi"
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || ( $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "$CI_DEFAULT_BRANCH" )
changes:
- "*.pl"
- "doc/**/*"
- "src/**/*"
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == "$CI_DEFAULT_BRANCH"
variables:
NAME: latest
- if: $CI_COMMIT_TAG
variables:
NAME: $CI_COMMIT_REF_SLUG
- when: never
artifacts:
paths: ["${BUILD_DIR}/webapi-docs.zip"]
name: "webapi-${NAME}-docs"
dependencies: []
needs: ["documentation:prepare_container"]
system_test:prepare_container:
stage: pre_build
variables:
CACHE_OPTION: --cache-from "${CI_REGISTRY_IMAGE}/${SYSTEM_TEST_IMAGE}:${CI_COMMIT_REF_SLUG}"
script:
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" ${CI_REGISTRY}
- docker image pull "${CI_REGISTRY_IMAGE}/${SYSTEM_TEST_IMAGE}:${CI_COMMIT_REF_SLUG}" || true
- docker build --tag "${CI_REGISTRY_IMAGE}/${SYSTEM_TEST_IMAGE}:${CI_COMMIT_REF_SLUG}" ${CACHE_OPTION} --build-arg "SWI_VERSION=$SWI_VERSION" - < docker/Dockerfile.system_test
- docker push "${CI_REGISTRY_IMAGE}/${SYSTEM_TEST_IMAGE}:${CI_COMMIT_REF_SLUG}"
tags:
- docker
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& $FORCE_SYSTEM_TESTS == "yes"
- if: $CI_COMMIT_TAG
variables:
CACHE_OPTION: --no-cache
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == "$CI_DEFAULT_BRANCH"
- if: $CI_PIPELINE_SOURCE == "push"
&& ($CI_OPEN_MERGE_REQUESTS == null || $CI_OPEN_MERGE_REQUESTS == "")
&& $FORCE_SYSTEM_TESTS == "yes"
.system_test:run:
stage: validate
image: ${CI_REGISTRY_IMAGE}/${SYSTEM_TEST_IMAGE}:${CI_COMMIT_REF_SLUG}
before_script:
- node --version
- newman --version
- swipl --version
script:
- swipl daemon.pl --user nobody
- newman run tests/api/${TEST_NAME}-tests.json -e tests/api/env.json --reporters junit --reporter-junit-export="api-report.xml"
- swipl daemon.pl --shutdown
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& $FORCE_SYSTEM_TESTS == "yes"
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == "push"
&& $CI_COMMIT_BRANCH == "$CI_DEFAULT_BRANCH"
- if: $CI_PIPELINE_SOURCE == "push"
&& ($CI_OPEN_MERGE_REQUESTS == null || $CI_OPEN_MERGE_REQUESTS == "")
&& $FORCE_SYSTEM_TESTS == "yes"
needs: ["system_test:prepare_container"]
artifacts:
when: always
reports:
junit: api-report.xml
.system_test:run_with_data:
extends: .system_test:run
script:
- swipl daemon.pl --user nobody
- newman run tests/api/${TEST_NAME}-tests.json -e tests/api/env.json -d tests/api/${TEST_NAME}-data.json --reporters junit --reporter-junit-export="api-report.xml"
- swipl daemon.pl --shutdown
.system_test:run_with_data_and_db:
extends: .system_test:run
script:
- cp -f tests/api/${TEST_NAME}-theory_bg.db theory_bg.db
- chown webapi theory_bg.db
- swipl daemon.pl --user webapi
- newman run tests/api/${TEST_NAME}-tests.json -e tests/api/env.json -d tests/api/${TEST_NAME}-data.json --reporters junit --reporter-junit-export="api-report.xml"
- swipl daemon.pl --shutdown
.system_test:run_with_db:
extends: .system_test:run
script:
- cp -f tests/api/${TEST_NAME}-theory_bg.db theory_bg.db
- chown webapi theory_bg.db
- swipl daemon.pl --user webapi
- newman run tests/api/${TEST_NAME}-tests.json -e tests/api/env.json --reporters junit --reporter-junit-export="api-report.xml"
- swipl daemon.pl --shutdown
system_test:up:
extends: .system_test:run
variables:
TEST_NAME: up_and_serving
system_test:endpoint_bg@add:
extends: .system_test:run_with_data
variables:
TEST_NAME: endpoint_bg@add
system_test:endpoint_bg@remove:
extends: .system_test:run_with_data_and_db
variables:
TEST_NAME: endpoint_bg@remove
system_test:endpoint_bg@clear:
extends: .system_test:run_with_db
variables:
TEST_NAME: endpoint_bg@clear
system_test:endpoint_bg@show:
extends: .system_test:run_with_data_and_db
variables:
TEST_NAME: endpoint_bg@show
system_test:endpoint_irrelevant@file:
extends: .system_test:run_with_data_and_db
variables:
TEST_NAME: endpoint_irrelevant@file
allow_failure: true # see issue #63
system_test:endpoint_explain:
extends: .system_test:run_with_data_and_db
variables:
TEST_NAME: endpoint_explain
allow_failure: true # see issue #63
system_test:robust against wrong method:
extends: .system_test:run_with_data
variables:
TEST_NAME: robust_wrong_method
system_test:robust against wrong body:
extends: .system_test:run_with_data
variables:
TEST_NAME: robust_wrong_content_payload
allow_failure: true # see issue #61
system_test:robust against superfluous payload:
extends: .system_test:run_with_data
variables:
TEST_NAME: robust_wrong_content_empty
allow_failure: true # see issue #61
system_test:bg robust against non-item payload:
extends: .system_test:run_with_data
variables:
TEST_NAME: robust_bg_non_item_payload
system_test:irrelevant robust against non-path payload:
extends: .system_test:run_with_data
variables:
TEST_NAME: robust_irrelevant@file_non_path_payload
allow_failure: true # see issue #64
system_test:explain robust against non-path payload:
extends: .system_test:run_with_data
variables:
TEST_NAME: robust_explain_non_path_payload
# If no FORCE_... variable is set to "yes", no pipeline is created for merge
# requests targetting a non-default branch. Thus, the MR cannot be merged. This
# dummy job remedies the missing pipeline.
dummy for MR:
stage: deploy
script: ["true"]
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
&& $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != $CI_DEFAULT_BRANCH
&& $FORCE_UNIT_TESTS != "yes"
&& $FORCE_INTEGRATION_TESTS != "yes"
&& $FORCE_SYSTEM_TESTS != "yes"
&& $FORCE_DOCKER_BUILD != "yes"
......@@ -2,35 +2,43 @@
In this document, we will describe the general input output systematics of the WebAPI and its defined endpoints for interaction. Each category will be detailed in its own section below. For each endpoint detailed in the sections, we will give the expected HTTP request method, handled parameters, the expected body, possible HTTP return codes, the response body on success, and give an example call using the [curl command line tool](https://curl.se/).
1. [JSON Types and Objects ](<#json_types>)
*Categories*:
2. [Background Knowledge Manipulation](<#bg>)
3. [Irrelevance](<#irrelevance>)
4. [Server Information](<#server>)
5. [Documentation](<#documentation>)
In general, the request bodies (if required) and responses are formatted as JSON documents.
Thus, we will present custom JSON types and objects used throughout the endpoint descriptions first.
For limitations on JSON parsing and generation see section [Limitations](<#limitations>).
The general input and output of the API is implemented with request/response methods that entail a body formatted as JSON. Therefore we will present custom JSON types and objects used throughout the endpoint descriptions first.
## JSON Types and Objects {#json_types}
Besides the usual JSON types (string, number, object, array, boolean, and null),
Besides the usual JSON types (string, integer, number, object, array, boolean, and null),
we use the following type definitions in this documentation:
$ integer: An integer number.
$ nonnegative integer: An integer greater than or equal to 0.
$ Path: A string specifying a path. Path delimiter is the slash =|"/"|=.
A Path is interpreted as pseudo-absolute path. That means that every
path is considered absolute and not interpreted relative to some
other path.
For example the path =|"A/B"|= is interpreted as =B= in
directory =A=, where =A= itself is in no other directory. Thus, =A=
is assumed to be _|a|_(!) root directory. The empty string (=|""|=)
is not a valid Path. The *nix root is represented by a single slash
(=|"/"|=). No other Path may end in a slash!
$ Path: A pseudo-absolute file system path (see [Path](<#json_path>)).
$ File: An object representing a file on disk (see [File](<#json_file>)).
$ Directory: An object representing a directory on disk (see [Directory](<#json_directory>)).
$ Item: An object representing a file or a directory on disk.
$ Manipulation Response: A family of objects used as response in background manipulation (see [Manipulation Response](<#json_response>)).
$ Item: An object representing either a file or a directory on disk.
$ Error Response: The response body returned if the server encounters an error (see [Error Response](<#json_error>)).
### Path {#json_path}
A _Path_ is a string specifying a file system path. Path delimiter is the slash =|"/"|=.
A Path is interpreted as pseudo-absolute path. That means that every
path is considered absolute and not interpreted relative to some
other path.
For example the path =|"A/B"|= is interpreted as =B= in
directory =A=, where =A= itself is in no other directory. Thus, =A=
is assumed to be _|a|_(!) root directory. The empty string (=|""|=)
is not a valid Path. The *nix root is represented by a single slash
(=|"/"|=). No other Path may end in a slash!
A _Path_ follows [this JSON schema](<schema/type-path-schema.json>).
### File {#json_file}
A file is represented as a JSON object with the following properties:
......@@ -56,26 +64,16 @@ A directory is represented as a JSON object with the following properties:
[JSON Example for a valid directory](<schema/type-directory-example.json>), accompanying schema definition [here](<schema/type-directory-schema.json>).
### Manipulation Response {#json_response}
The API response after a completed action is represented as a JSON object with the following properties: