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: stages:
- test - unit_test1
- build - unit_test2
- validate - integration_test
- deploy - pre_build
- build
- validate
- deploy
variables: 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 # Template for Prolog test jobs
.prolog_test: .prolog_test:
image: swipl:$SWI_VERSION image: swipl:$SWI_VERSION
stage: test script:
script: - swipl "tests/plunit/${TEST_FILE}" > "${REPORT_PATH}"
- swipl -s "tests/${TEST_FILE}" -t "run_all_tests" > "${REPORT_PATH}" timeout: 15m
timeout: 15m artifacts:
artifacts: paths:
paths: - "$REPORT_PATH"
- "$REPORT_PATH" expire_in: 3 days
expire_in: 3 days
test_theory_common: test_theory_common:
extends: .prolog_test extends: .prolog_test
variables: stage: unit_test1
TEST_FILE: irrelevance_common.plt variables:
REPORT_PATH: coverage_irrelevance_common TEST_FILE: irrelevance_common.plt
rules: REPORT_PATH: coverage_irrelevance_common
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || ( $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH ) rules:
changes: - if: $CI_PIPELINE_SOURCE == "merge_request_event"
- src/version.pl && ( $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
- irrelevance_common.pl || $FORCE_UNIT_TESTS == "yes" )
- tests/irrelevance_common.plt changes:
- tests/test_utils.pl - irrelevance_common.pl
- tests/data_theory_common.pl - tests/plunit/irrelevance_common.plt
- if: $CI_COMMIT_TAG - tests/plunit/test_utils.pl
- when: never - 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: test_web_api:
extends: .prolog_test extends: .prolog_test
variables: stage: unit_test2
TEST_FILE: web_api.plt variables:
REPORT_PATH: coverage_web_api TEST_FILE: web_api.plt
rules: REPORT_PATH: coverage_web_api
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || ( $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH ) rules:
changes: - if: $CI_PIPELINE_SOURCE == "merge_request_event"
- src/version.pl && ( $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
- src/web_api.pl || $FORCE_UNIT_TESTS == "yes" )
- src/web_api/*.pl changes:
- tests/web_api.plt - src/web_api.pl
- tests/test_utils.pl - src/web_api/*.pl
- tests/web_api/*.plt - tests/plunit/web_api.plt
- if: $CI_COMMIT_TAG - tests/plunit/test_utils.pl
- when: never - 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: test_types:
extends: .prolog_test extends: .prolog_test
variables: stage: unit_test2
TEST_FILE: types.plt variables:
REPORT_PATH: coverage_types TEST_FILE: types.plt
rules: REPORT_PATH: coverage_types
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || ( $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH ) rules:
changes: - if: $CI_PIPELINE_SOURCE == "merge_request_event"
- src/version.pl && ( $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
- src/types.pl || $FORCE_UNIT_TESTS == "yes" )
- tests/types.plt changes:
- tests/types/*.plt - src/types.pl
- tests/test_utils.pl - tests/plunit/types.plt
- if: $CI_COMMIT_TAG - tests/plunit/types/*.plt
- when: never - 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: container:build:
stage: build stage: build
script: script:
- "docker build --tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} ." - docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" ${CI_REGISTRY}
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" ${CI_REGISTRY} - docker image pull "${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:latest" || true
- "docker push ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}" - docker image pull "${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:$CI_COMMIT_REF_SLUG" || true
tags: - "docker build --tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} ${CACHE_OPTION} ."
- docker - "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: container:validate:
stage: validate stage: validate
image: image:
name: byrnedo/alpine-curl name: postman/newman:5.2.3-alpine
entrypoint: ["/bin/sh", "-c"] entrypoint: ["/bin/sh", "-c"]
services: services:
- name: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} - name: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}
alias: tested_container alias: webapi
script: before_script:
- curl -fsS --location --output /dev/null --retry 50 --retry-delay 5 --retry-connrefused --retry-max-time 300 "http://tested_container/state" - node --version
needs: ["container:build"] - 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: container:deploy:
...@@ -97,27 +262,42 @@ container:deploy: ...@@ -97,27 +262,42 @@ container:deploy:
script: script:
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" ${CI_REGISTRY} - docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" ${CI_REGISTRY}
- "docker image pull ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}" - "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 tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} ${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:${DEPLOY_TAG}"
- "docker push ${CI_REGISTRY_IMAGE}/${DEPLOY_IMAGE}:${DEPLOY_TAG}" - "docker push ${CI_REGISTRY_IMAGE}/${CONTAINER_DEPLOY_IMAGE}:${DEPLOY_TAG}"
- "docker logout ${DEPLOY_REGISTRY}" - "docker logout ${DEPLOY_REGISTRY}"
variables:
DEPLOY_IMAGE: "webapi"
tags: tags:
- docker - docker
rules: rules:
- if: $CI_COMMIT_TAG - if: $CI_COMMIT_TAG
variables: variables:
DEPLOY_TAG: $CI_COMMIT_REF_SLUG 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: variables:
DEPLOY_TAG: latest DEPLOY_TAG: latest
- if: $CI_COMMIT_BRANCH - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH
&& $FORCE_DOCKER_BUILD == "yes"
variables: variables:
DEPLOY_TAG: $CI_COMMIT_REF_SLUG 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 stage: build
image: swipl:$SWI_VERSION image: swipl:$SWI_VERSION
variables: variables:
...@@ -129,18 +309,182 @@ standalone documentation: ...@@ -129,18 +309,182 @@ standalone documentation:
- pip3 install lxml - pip3 install lxml
- utils/generate_documentation.sh "$BUILD_DIR" "webapi" - utils/generate_documentation.sh "$BUILD_DIR" "webapi"
rules: rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || ( $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "$CI_DEFAULT_BRANCH" ) - if: $CI_PIPELINE_SOURCE == "push"
changes: && $CI_COMMIT_BRANCH == "$CI_DEFAULT_BRANCH"
- "*.pl"
- "doc/**/*"
- "src/**/*"
variables: variables:
NAME: latest NAME: latest
- if: $CI_COMMIT_TAG - if: $CI_COMMIT_TAG
variables: variables:
NAME: $CI_COMMIT_REF_SLUG NAME: $CI_COMMIT_REF_SLUG
- when: never
artifacts: artifacts:
paths: ["${BUILD_DIR}/webapi-docs.zip"] paths: ["${BUILD_DIR}/webapi-docs.zip"]
name: "webapi-${NAME}-docs" 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 @@ ...@@ -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/). 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>) 2. [Background Knowledge Manipulation](<#bg>)
3. [Irrelevance](<#irrelevance>) 3. [Irrelevance](<#irrelevance>)
4. [Server Information](<#server>) 4. [Server Information](<#server>)
5. [Documentation](<#documentation>) 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} ## 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: we use the following type definitions in this documentation:
$ integer: An integer number.
$ nonnegative integer: An integer greater than or equal to 0. $ nonnegative integer: An integer greater than or equal to 0.
$ Path: A string specifying a path. Path delimiter is the slash =|"/"|=. $ Path: A pseudo-absolute file system path (see [Path](<#json_path>)).
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!