diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml
new file mode 100644
index 0000000..5992ce6
--- /dev/null
+++ b/.github/workflows/backport.yaml
@@ -0,0 +1,46 @@
+name: Pull Request Backporting using Git Backporting
+
+on:
+ pull_request_target:
+ types:
+ - closed
+ - labeled
+
+env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ NO_SQUASH_OPTION: true
+
+jobs:
+ backporting:
+ name: "Backporting"
+ concurrency:
+ group: backporting-${{ github.head_ref }}
+ cancel-in-progress: true
+ # Only react to merged PRs for security reasons.
+ # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
+ if: >
+ github.event.pull_request.merged
+ && (
+ github.event.action == 'closed'
+ && (contains(github.event.pull_request.labels.*.name, 'backport')
+ || contains(github.event.pull_request.labels.*.name, 'backport-squash'))
+ || (
+ github.event.action == 'labeled'
+ && contains(github.event.label.name, 'backport')
+ )
+ )
+ runs-on: ubuntu-latest
+ steps:
+ - name: Override no-squash option
+ if: >
+ (github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'backport-squash'))
+ || (github.event.action == 'labeled' && contains(github.event.label.name, 'backport-squash'))
+ shell: bash
+ run: |
+ echo "NO_SQUASH_OPTION=false" >> $GITHUB_ENV
+ - name: Backporting
+ uses: kiegroup/git-backporting@v4.5.3
+ with:
+ target-branch: 0.12.x
+ pull-request: ${{ github.event.pull_request.url }}
+ no-squash: ${{ env.NO_SQUASH_OPTION }}
diff --git a/.github/workflows/check-openapi-change.yaml b/.github/workflows/check-openapi-change.yaml
new file mode 100644
index 0000000..227e515
--- /dev/null
+++ b/.github/workflows/check-openapi-change.yaml
@@ -0,0 +1,70 @@
+# This workflow will fetch the new openapi from the provided branch of https://github.com/Hyperfoil/Horreum and based on
+# that it will re-generate the Horreum raw client and check the build/tests are still working.
+# It could be tested running `gh act workflow_dispatch -e ./test/gha_workflows/workflow_dispatch_event_example.json`.
+name: Update Horreum auto-generated client
+
+on:
+ workflow_dispatch:
+ inputs:
+ branch:
+ description: Branch or tag of https://github.com/Hyperfoil/Horreum
+ required: true
+ # this event should be triggered by Horreum repo using peter-evans/repository-dispatch@v2
+ repository_dispatch:
+ types: [ detected-horreum-openapi-change ]
+
+jobs:
+ check-openapi-change:
+ name: check-openapi-change ${{ github.event.client_payload.branch }}
+ runs-on: ubuntu-latest
+ env:
+ FORCE_COLOR: "1"
+ PRE_COMMIT_COLOR: "always"
+ strategy:
+ fail-fast: false
+ matrix:
+ python: [ "3.9", "3.10", "3.11" ]
+ steps:
+ - name: Fetch Horreum branch
+ id: fetch-horreum-branch
+ run: |
+ if [ "${{ github.event_name }}" = "repository_dispatch" ]; then
+ echo "horreum_branch=${{ github.event.client_payload.branch }}" >> $GITHUB_OUTPUT
+ elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
+ echo "horreum_branch=${{ github.event.inputs.branch }}" >> $GITHUB_OUTPUT
+ else
+ echo "Unknown event: ${{ github.event_name }}"
+ exit 1
+ fi
+ - name: Fetch client branch
+ id: fetch-client-branch
+ run: |
+ if [ "${{ steps.fetch-horreum-branch.outputs.horreum_branch }}" = "master" ]; then
+ echo "horreum_client_branch=main" >> $GITHUB_OUTPUT
+ else
+ echo "horreum_client_branch=${{ steps.fetch-horreum-branch.outputs.horreum_branch }}" >> $GITHUB_OUTPUT
+ fi
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ steps.fetch-client-branch.outputs.horreum_client_branch }}
+ persist-credentials: false
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python }}
+ - name: Upgrade pip
+ run: |
+ pip install --constraint=./dev-constraints.txt pip
+ pip --version
+ - name: Install poetry
+ run: |
+ pip install --constraint=./dev-constraints.txt poetry
+ poetry --version
+ - name: Install Nox
+ run: |
+ pip install --constraint=./dev-constraints.txt nox nox-poetry
+ nox --version
+ - name: Generate horreum client
+ run: make HORREUM_BRANCH=${{ steps.fetch-horreum-branch.outputs.horreum_branch }} generate
+ - name: Test horreum
+ run: nox --python=${{ matrix.python }} -s tests
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 4caa2fd..dec6b6e 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -1,17 +1,17 @@
# This workflow will run the full CI for the Horreum python library including the build and the tests execution
-# This is going to be triggered on every pull request as well as on main branch.
-# TODO: trigger tests once implemented
+# This is going to be triggered on every pull request as well as on all stable branches (e.g., main and 0.12.x).
name: Python client ci
on:
push:
branches:
- main
+ - 0.12.x
pull_request:
jobs:
test:
- name: ${{ matrix.session }} ${{ matrix.python }}
+ name: test/${{ matrix.python }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -27,7 +27,19 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- - name: Install development dependencies
- run: pip install -r dev-requirements.txt
- - name: Build python library
- run: poetry build
+ - name: Upgrade pip
+ run: |
+ pip install --constraint=./dev-constraints.txt pip
+ pip --version
+ - name: Install poetry
+ run: |
+ pip install --constraint=./dev-constraints.txt poetry
+ poetry --version
+ - name: Install Nox
+ run: |
+ pip install --constraint=./dev-constraints.txt nox nox-poetry
+ nox --version
+ - name: Generate horreum client
+ run: make generate
+ - name: Test horreum
+ run: nox --python=${{ matrix.python }} -s tests
diff --git a/.github/workflows/generate-client.yaml b/.github/workflows/generate-client.yaml
deleted file mode 100644
index 8b25a5e..0000000
--- a/.github/workflows/generate-client.yaml
+++ /dev/null
@@ -1,54 +0,0 @@
-# This workflow will fetch the new openapi from the provided branch of https://github.com/Hyperfoil/Horreum and based on
-# that it will re-generate the Horreum raw client and creates a new pull request against the corresponding branch here.
-# It could be tested running `gh act workflow_dispatch -e ./test/workflow_dispatch_event_example.json`. Remember to
-# comment out the pull request creation :)
-name: Autogenerate Horreum client
-
-on:
- workflow_dispatch:
- inputs:
- branch:
- description: Branch or tag of https://github.com/Hyperfoil/Horreum
- required: true
- repository_dispatch:
- types: [ generate-horreum-client ]
-
-jobs:
- generate:
- runs-on: ubuntu-latest
- steps:
- - name: Fetch branch
- id: fetch-branch
- run: |
- if [ "${{ github.event_name }}" = "repository_dispatch" ]; then
- # Generated by peter-evans/repository-dispatch@v3
- echo "HORREUM_BRANCH=${{ github.event.client_payload.branch }}" >> $GITHUB_OUTPUT
- elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
- echo "HORREUM_BRANCH=${{ github.event.inputs.branch }}" >> $GITHUB_OUTPUT
- else
- echo "Unknown event: ${{ github.event_name }}"
- exit 1
- fi
- - uses: actions/checkout@v4
- with:
- persist-credentials: false
- - uses: actions/setup-python@v5
- with:
- python-version: '3.10'
- cache: 'pip'
- - name: Install development dependencies
- run: pip install -r dev-requirements.txt
- - name: Generate horreum client
- run: make HORREUM_BRANCH=${{ steps.fetch-branch.outputs.HORREUM_BRANCH }} generate
- - run: git --no-pager diff
- - name: Create Pull Request
- uses: gr2m/create-or-update-pull-request-action@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- title: Generate Horreum client from github.com/Hyperfoil/Horreum:${{ steps.fetch-branch.outputs.HORREUM_BRANCH }}
- body: |
- There is a new change in the openapi spec of Horreum in branch ${{ steps.fetch-branch.outputs.HORREUM_BRANCH }}.
- Verify that there are no breaking changes.
- branch: horreum-openapi-${{ steps.fetch-branch.outputs.HORREUM_BRANCH }}
- commit-message: Horreum openapi client updated
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index c8a971c..8e5fa8a 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -1,28 +1,25 @@
-# This workflow will build the python distribution and it will publish to Pypi
-# This is going to be triggered on on every tag `v*`, e.g., `v0.13`.
-# TODO: trigger tests once implemented, to ensure everything is working before publishing
+# This workflow will build the python distribution, and it will publish to Pypi
+# This is going to be triggered on every tag `v*`, e.g., `v0.13`.
name: Publish Horreum library
on:
push:
tags:
- v*
+ workflow_dispatch:
jobs:
- test:
- name: ${{ matrix.session }} ${{ matrix.python }}
+ publish:
+ name: Publish horreum package
runs-on: ubuntu-latest
+ permissions:
+ id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
env:
FORCE_COLOR: "1"
+ PY_VERSION: "3.10"
steps:
- name: Check out the repository
uses: actions/checkout@v4
- - name: Set up Python
- uses: actions/setup-python@v5
- with:
- python-version: "3.10"
- - name: Install development dependencies
- run: pip install -r dev-requirements.txt
- name: Check version coherence
run: |
PROJECT_VERSION=$(poetry version | cut -d' ' -f2)
@@ -31,8 +28,29 @@ jobs:
echo "::error title='$GIT_TAG tag does not match project version'::"
exit 1
fi
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ env.PY_VERSION }}
+ - name: Upgrade pip
+ run: |
+ pip install --constraint=./dev-constraints.txt pip
+ pip --version
+ - name: Install poetry
+ run: |
+ pip install --constraint=./dev-constraints.txt poetry
+ poetry --version
+ - name: Install Nox
+ run: |
+ pip install --constraint=./dev-constraints.txt nox nox-poetry
+ nox --version
+ - name: Generate horreum client
+ # HORREUM_BRANCH must be properly set to the Horreum branch you want to fetch the openapi
+ run: make generate
+ - name: Test horreum
+ run: nox --python=${{ env.PY_VERSION }} -s tests
- name: Build python library
- run: make generate && poetry build --ansi
+ run: poetry build --ansi
- name: Publish package on PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
diff --git a/.gitignore b/.gitignore
index bdd715c..e82eca0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,9 @@ bin/
# Kiota
**/.kiota.log
+
+# Openapi
+openapi/openapi.yaml
+
+# Generated code
+src/horreum/raw_client/**
diff --git a/GET_STARTED.md b/GET_STARTED.md
deleted file mode 100644
index a01a281..0000000
--- a/GET_STARTED.md
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-# Get Started Guide
-
-
-
-In this document you can find all information to get started using the Horreum python library from scratch.
-
-Right now the library is not published anywhere, therefore the only way to install it is from source.
-
----
-## Prerequisites
-
-* Python environment, e.g., `pyenv` or `miniconda` with all development dependencies installed:
-```bash
-pip install -r dev-requirements.txt
-```
-
-## Installation
-
-Once all dependencies are installed simply build the `whl` by running:
-
-```bash
-poetry build
-```
-
-Now you can install the local build of `horreum` python client:
-
-```bash
-pip install dist/horreum-*.dev0-py3-none-any.whl --force-reinstall
-```
-
-## Usage
-
-```bash
->>> import asyncio
-
-# Import the constructor function
->>> from horreum.horreum_client import new_horreum_client
-
-# Initialize the client
->>> client = await new_horreum_client(base_url="http://localhost:8080", username="..", password="..")
-
-# Call the api using the underlying raw client, in this case retrieve the Horreum server version
->>> await client.raw_client.api.config.version.get()
-VersionInfo(additional_data={}, privacy_statement=None, start_timestamp=1710864862253, version='0.13.0')
-```
-
-The previous api call is equivalent to the following `cURL`:
-```bash
-curl --silent -X 'GET' 'http://localhost:8080/api/config/version' -H 'accept: application/json' | jq '.'
-```
diff --git a/Makefile b/Makefile
index 8a3a6b6..1172bde 100644
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,8 @@ KIOTA_VERSION ?= "v1.12.0"
HORREUM_BRANCH ?= "master"
HORREUM_OPENAPI_PATH ?= "https://raw.githubusercontent.com/Hyperfoil/Horreum/${HORREUM_BRANCH}/docs/site/content/en/openapi/openapi.yaml"
GENERATED_CLIENT_PATH = "${PROJECT_PATH}/src/horreum/raw_client"
+OPENAPI_PATH = "${PROJECT_PATH}/openapi"
+OPENAPI_SPEC = "${OPENAPI_PATH}/openapi.yaml"
.PHONY: help
help: ## Display this help.
@@ -36,9 +38,13 @@ help: ## Display this help.
##@ Development
+.PHONY: clean-bin
+clean-bin: ## Clean external tools
+ @rm -rf ${PROJECT_BIN}
+
.PHONY: clean
-clean: ## Clean external tools and output dirs
- @rm -rf ${PROJECT_BIN} ${PROJECT_DIST} ${GENERATED_CLIENT_PATH}/api ${GENERATED_CLIENT_PATH}/models ${GENERATED_CLIENT_PATH}/horreum_raw_client.py ${GENERATED_CLIENT_PATH}/kiota-lock.json
+clean: ## Clean output directories
+ @rm -rf ${PROJECT_DIST} ${GENERATED_CLIENT_PATH} ${OPENAPI_PATH}
.PHONY: kiota
kiota: ${PROJECT_BIN}/kiota ## Install kiota tool under ${PROJECT_PATH}/bin
@@ -58,10 +64,17 @@ ${PROJECT_BIN}/kiota:
.PHONY: tools
tools: kiota ## Install external tools.
+${OPENAPI_SPEC}:
+ @{\
+ set -e ;\
+ mkdir -p ${OPENAPI_PATH} ;\
+ echo "fetching openapi spec from ${HORREUM_OPENAPI_PATH}" ;\
+ curl -sSfL -o ${OPENAPI_SPEC} ${HORREUM_OPENAPI_PATH} ;\
+ }
+
.PHONY: generate
-generate: tools ## Generate the Horreum client
+generate: tools ${OPENAPI_SPEC} ## Generate the Horreum client
@{\
set -e ;\
- curl -sSfL -o ${PROJECT_PATH}/openapi/openapi.yaml ${HORREUM_OPENAPI_PATH} ;\
- ${PROJECT_BIN}/kiota generate -l python -c HorreumRawClient -n raw_client -d ${PROJECT_PATH}/openapi/openapi.yaml -o ${GENERATED_CLIENT_PATH} ;\
+ ${PROJECT_BIN}/kiota generate -l python -c HorreumRawClient -n raw_client -d ${OPENAPI_PATH}/openapi.yaml -o ${GENERATED_CLIENT_PATH} ;\
}
diff --git a/README.md b/README.md
index 68e5daf..d1490fd 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ Horreum python client is a high-level python library to interact with [Horreum](
The raw client is generated using [kiota](https://github.com/microsoft/kiota) openapi generator tool starting from
the [Horreum OpenAPI spec](https://github.com/Hyperfoil/Horreum/blob/master/docs/site/content/en/openapi/openapi.yaml).
-Refer to the [get started guide](./GET_STARTED.md) for comprehensive instructions on installing and utilizing this library.
+Refer to the [get started guide](docs/GET_STARTED.md) for comprehensive instructions on installing and utilizing this library.
## What is Horreum?
@@ -42,9 +42,10 @@ Contributions to `horreum-client-python` Please check our [CONTRIBUTING.md](./CO
### Development
-Install all dev dependencies (consider using Python virtual environments):
+Install poetry dependency (consider using Python virtual environments):
```bash
-pip install -r dev-requirements.txt
+pip install --constraint=./dev-constraints.txt poetry
+poetry --version
```
Generate source files
@@ -58,15 +59,32 @@ poetry build
```
#### Tests
+Tests can be executed using [nox](https://nox.thea.codes/en/stable/) sessions.
-Right now tests are not automated, therefore you need to start up the Horreum server manually,
+To install it in your local environment, please run:
+```bash
+pip install --constraint=./dev-constraints.txt nox nox-poetry
+nox --version
+```
+
+To check available sessions, run:
+```bash
+nox -l
+```
+
+And execute them by running:
+```
+nox -s
+```
+
+Right now integrations tests are not fully automated, therefore you need to start up the Horreum server manually,
you can check more details in [Horreum README](https://github.com/Hyperfoil/Horreum/blob/master/README.md#getting-started-with-development-server).
> **_NOTE_**: The database should be empty to get all tests working
Once the Horreum server is up and running on `localhost:8080`, you can trigger integration tests by running:
```bash
-pytest test/
+nox -s its
```
### If you have any idea or doubt 👇
diff --git a/dev-constraints.txt b/dev-constraints.txt
new file mode 100644
index 0000000..e1ea1a2
--- /dev/null
+++ b/dev-constraints.txt
@@ -0,0 +1,7 @@
+pip==23.3.1
+nox==2024.3.2
+nox-poetry==1.0.3
+poetry==1.8.2
+pytest==8.1.1
+pytest-asyncio==0.23.6
+virtualenv==20.24.6
\ No newline at end of file
diff --git a/dev-requirements.txt b/dev-requirements.txt
deleted file mode 100644
index 60a3f21..0000000
--- a/dev-requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-poetry==1.8.2
-pytest==8.1.1
-pytest-asyncio==0.23.6
\ No newline at end of file
diff --git a/docs/GET_STARTED.md b/docs/GET_STARTED.md
new file mode 100644
index 0000000..3cd1d65
--- /dev/null
+++ b/docs/GET_STARTED.md
@@ -0,0 +1,92 @@
+
+
+# Getting Started
+
+
+
+In this document you can find all information to get started using the Horreum python library from scratch.
+
+> **NOTE**: At the moment of writing, the `horreum` package is not yet accessible on PyPI. Consequently, the sole method
+> for installation involves constructing it from source and subsequently installing the generated `wheel`.
+
+---
+## Prerequisites
+
+* Python environment, e.g., `pyenv` or `miniconda` with `poetry` dependency installed:
+```bash
+pip install --constraint=./dev-constraints.txt poetry
+poetry --version
+```
+
+## Installation
+
+Once all [prerequisites](#prerequisites) are satisfied, run the following commands.
+
+First of all, generate the Horreum client:
+
+```bash
+make generate
+```
+
+Then, simply build the _wheel_ by running:
+
+```bash
+poetry build
+```
+
+Now you can install the local build of `horreum` python client:
+
+```bash
+pip install dist/horreum-*.dev0-py3-none-any.whl --force-reinstall
+```
+
+## Usage
+
+Horreum Python library leverages the auto-generated client using [Kiota](https://github.com/microsoft/kiota) tool to translate all REST requests
+into python methods calls.
+
+Right now Horreum library does not expose any specific high-level api, but it simply offers the Kiota generated client
+which is made available through the `HorreumClient.raw_client` property.
+
+Check [Kiota python examples](https://github.com/microsoft/kiota-samples/tree/main/get-started/quickstart/python) to see
+how to interact with a Kiota auto-generated Python client.
+
+Here a very simple example:
+
+```bash
+>>> import asyncio
+
+# Import the constructor function
+>>> from horreum.horreum_client import new_horreum_client
+
+# Initialize the client
+>>> client = await new_horreum_client(base_url="http://localhost:8080", username="..", password="..")
+
+# Call the api using the underlying raw client, in this case retrieve the Horreum server version
+>>> await client.raw_client.api.config.version.get()
+VersionInfo(additional_data={}, privacy_statement=None, start_timestamp=1710864862253, version='0.13.0')
+```
+
+The previous api call is equivalent to the following `cURL`:
+```bash
+curl --silent -X 'GET' 'http://localhost:8080/api/config/version' -H 'accept: application/json' | jq '.'
+```
+
+Other examples can be found in the [test folder](../test), for instance:
+
+```bash
+# Import Horreum Test model
+>>> from horreum.raw_client.models.test import Test
+>>> from horreum.raw_client.models.protected_type_access import ProtectedType_access
+
+# Initialize the client
+>>> client = await new_horreum_client(base_url="http://localhost:8080", username="..", password="..")
+
+# Create new Horreum test
+>>> t = Test(name="TestName", description="Simple test", owner="dev-team", access=ProtectedType_access.PUBLIC)
+>>> created = await client.raw_client.api.test.post(t)
+Test(additional_data={}, access=, owner='dev-team', compare_url=None, datastore_id=1, description='Simple test', fingerprint_filter=None, fingerprint_labels=None, folder=None, id=12, name='TestName', notifications_enabled=True, timeline_function=None, timeline_labels=None, tokens=None, transformers=None)
+
+# Delete the Horreum test
+>>> await client.raw_client.api.test.by_id(12).delete()
+```
diff --git a/docs/RELEASE.md b/docs/RELEASE.md
new file mode 100644
index 0000000..2022a19
--- /dev/null
+++ b/docs/RELEASE.md
@@ -0,0 +1,77 @@
+# Release
+
+This document aims to describe how to perform a release of the Horreum python library.
+
+The versioning pattern should follow the [Horreum](https://github.com/Hyperfoil/Horreum)
+versioning scheme to keep coherence among all Horreum-related projects versions.
+
+## Procedure
+
+### Tag a new version
+
+Checkout to your branch, either a "stable" (e.g., `0.12.x`) or the `main` one.
+
+```bash
+git checkout origin/main
+```
+
+Update the project version:
+
+```bash
+poetry version patch
+```
+
+This will bump your version, from `0.12-dev` to `0.12`.
+
+To double-check the version, run:
+```bash
+poetry version
+# horreum 0.12
+```
+
+Commit the changes and tag a new version:
+```bash
+git add .
+git commit -m "Tag version 0.12"
+git tag v0.12
+```
+
+Ensure the tag is in the form of `v$(poetry version)`.
+
+Push changes and tag:
+```bash
+git push origin main
+git push origin v0.12
+```
+
+If you are releasing a new patch from a _stable_ branch all previous operations must be performed
+from _stable_ rather than from `main`.
+
+### Create stable branch
+
+> **NOTE**: If the _stable_ branch already exists, simply skip this step, as this means the following steps have already been done.
+
+To create a _stable_ branch from the `main` one, e.g., `0.12.x`, run the following commands.
+
+```bash
+git checkout origin/main -b 0.12.x
+git checkout origin/main
+```
+
+Update version to the next development one:
+```bash
+poetry version 0.13-dev
+```
+
+Commit the changes:
+```bash
+git add .
+git commit -m "Next is 0.13"
+```
+
+Push changes:
+```bash
+git push origin 0.12.x
+git push origin main
+```
+
diff --git a/noxfile.py b/noxfile.py
new file mode 100644
index 0000000..7052062
--- /dev/null
+++ b/noxfile.py
@@ -0,0 +1,43 @@
+import nox
+from nox_poetry import Session, session
+
+py_versions = ["3.9", "3.10", "3.11"]
+
+nox.needs_version = ">= 2021.6.6"
+nox.options.sessions = (
+ "tests",
+)
+
+
+@session(python=py_versions)
+def tests(s: Session):
+ """ Run unit tests """
+ s.install(".")
+ s.install(
+ "asyncio",
+ "pytest",
+ "pytest-asyncio"
+ )
+ # run tests
+ s.run(
+ "pytest",
+ "test/horreum_client_test.py",
+ *s.posargs
+ )
+
+
+@session(python=py_versions)
+def its(s: Session):
+ """ Run integration tests """
+ s.install(".")
+ s.install(
+ "asyncio",
+ "pytest",
+ "pytest-asyncio"
+ )
+ # run tests
+ s.run(
+ "pytest",
+ "test/horreum_client_it.py",
+ *s.posargs
+ )
diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml
deleted file mode 100644
index 92cd711..0000000
--- a/openapi/openapi.yaml
+++ /dev/null
@@ -1,4610 +0,0 @@
----
-openapi: 3.0.3
-info:
- title: Horreum REST API
- description: "Horreum automated change anomaly detection. For more information,\
- \ please see [https://horreum.hyperfoil.io/](https://horreum.hyperfoil.io/)"
- version: "0.13"
-tags:
-- name: Config
- description: Endpoint providing configuration for the Horreum System
- x-smallrye-profile-external: ""
-- name: Dataset
- description: Datasets are used as the basis for all change detection and reporting
- x-smallrye-profile-external: ""
-- name: Experiment
- description: Experiments allow users to apply change detection rules to two different
- datasets. This allows for pass/fail of KPIS based on A/B testing
- x-smallrye-profile-external: ""
-- name: Run
- description: Manage test runs. Runs are instances of results of a benchmark execution
- x-smallrye-profile-external: ""
-- name: Schema
- description: Manage schemas
- x-smallrye-profile-external: ""
-- name: Test
- description: Endpoint giving access to tests defined in Horreum.
- x-smallrye-profile-external: ""
-paths:
- /api/config/datastore:
- put:
- tags:
- - Config
- description: Update an existing Datastore definition
- operationId: updateDatastore
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Datastore'
- responses:
- "200":
- description: The ID of the updated Datastore
- content:
- application/json:
- schema:
- format: int32
- type: integer
- post:
- tags:
- - Config
- description: Create a new Datastore
- operationId: newDatastore
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Datastore'
- responses:
- "200":
- description: The ID for the new Datastore
- content:
- application/json:
- schema:
- format: int32
- type: integer
- /api/config/datastore/{id}:
- delete:
- tags:
- - Config
- description: Test a Datastore
- operationId: deleteDatastore
- parameters:
- - name: id
- in: path
- required: true
- schema:
- type: string
- responses:
- "204":
- description: No Content
- /api/config/datastore/{id}/test:
- get:
- tags:
- - Config
- description: Test a Datastore connection
- operationId: testDatastore
- parameters:
- - name: id
- in: path
- required: true
- schema:
- type: string
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatastoreTestResponse'
- /api/config/datastore/{team}:
- get:
- tags:
- - Config
- description: Obtain list of configured datastores for particular team
- operationId: datastores
- parameters:
- - name: team
- in: path
- description: name of the team to search for defined datastores
- required: true
- schema:
- type: string
- example: perf-team
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/Datastore'
- /api/config/keycloak:
- get:
- tags:
- - Config
- description: Obtain configuration information about keycloak server securing
- Horreum instance
- operationId: keycloak
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/KeycloakConfig'
- /api/config/version:
- get:
- tags:
- - Config
- description: Obtain version of the running Horreum instance
- operationId: version
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/VersionInfo'
- /api/dataset/bySchema:
- get:
- tags:
- - Dataset
- description: "Retrieve a paginated list of Datasets, with total count, by Schema"
- operationId: listBySchema
- parameters:
- - name: uri
- in: query
- description: Schema URI
- required: true
- schema:
- type: string
- example: uri:techempower:0.1
- - name: limit
- in: query
- description: limit the number of results
- schema:
- format: int32
- type: integer
- example: 20
- - name: page
- in: query
- description: filter by page number of a paginated list of Schemas
- schema:
- format: int32
- type: integer
- example: 2
- - name: sort
- in: query
- description: Field name to sort results
- schema:
- default: start
- type: string
- example: name
- - name: direction
- in: query
- description: Sort direction
- schema:
- $ref: '#/components/schemas/SortDirection'
- example: Ascending
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatasetList'
- /api/dataset/list/{testId}:
- get:
- tags:
- - Dataset
- description: "Retrieve a paginated list of Datasets, with total count, by Test"
- operationId: listByTest
- parameters:
- - name: testId
- in: path
- description: Test ID of test to retrieve list of Datasets
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: filter
- in: query
- description: JOSN Filter expression to apply to query
- schema:
- type: string
- example:
- buildID: 111111
- - name: limit
- in: query
- description: limit the number of results
- schema:
- format: int32
- type: integer
- example: 20
- - name: page
- in: query
- description: filter by page number of a paginated list of Schemas
- schema:
- format: int32
- type: integer
- example: 2
- - name: sort
- in: query
- description: Field name to sort results
- schema:
- type: string
- example: name
- - name: direction
- in: query
- description: Sort direction
- schema:
- $ref: '#/components/schemas/SortDirection'
- example: Ascending
- - name: viewId
- in: query
- description: Optional View ID to filter datasets by view
- schema:
- format: int32
- type: integer
- example: 202
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatasetList'
- /api/dataset/{datasetId}/labelValues:
- get:
- tags:
- - Dataset
- operationId: labelValues
- parameters:
- - name: datasetId
- in: path
- required: true
- schema:
- format: int32
- type: integer
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/LabelValue'
- /api/dataset/{datasetId}/previewLabel:
- post:
- tags:
- - Dataset
- operationId: previewLabel
- parameters:
- - name: datasetId
- in: path
- required: true
- schema:
- format: int32
- type: integer
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Label'
- required: true
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/LabelPreview'
- /api/dataset/{datasetId}/summary:
- get:
- tags:
- - Dataset
- operationId: getSummary
- parameters:
- - name: datasetId
- in: path
- required: true
- schema:
- format: int32
- type: integer
- - name: viewId
- in: query
- schema:
- format: int32
- type: integer
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatasetSummary'
- /api/dataset/{id}:
- get:
- tags:
- - Dataset
- description: Retrieve Dataset by ID
- operationId: getDataset
- parameters:
- - name: id
- in: path
- description: Dataset ID to retrieve
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "404":
- description: No Dataset with the given id was found
- content:
- application/json: {}
- "200":
- description: JVM system properties of a particular host.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Dataset'
- /api/experiment/models:
- get:
- tags:
- - Experiment
- description: Retrieve a list of Condition Config models
- operationId: models
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/ConditionConfig'
- /api/experiment/run:
- get:
- tags:
- - Experiment
- description: Run an experiment for a given dataset and experiment profile
- operationId: runExperiments
- parameters:
- - name: datasetId
- in: query
- description: The dataset to run the experiment on
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: Array of experiment results
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/ExperimentResult'
- /api/experiment/{testId}/profiles:
- get:
- tags:
- - Experiment
- description: Retrieve Experiment Profiles by Test ID
- operationId: profiles
- parameters:
- - name: testId
- in: path
- description: Test ID to retrieve Experiment Profiles for
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/ExperimentProfile'
- post:
- tags:
- - Experiment
- description: 'Save new or update existing Experiment Profiles for a Test '
- operationId: addOrUpdateProfile
- parameters:
- - name: testId
- in: path
- description: Test ID to retrieve Experiment Profiles for
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ExperimentProfile'
- required: true
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- format: int32
- type: integer
- /api/experiment/{testId}/profiles/{profileId}:
- delete:
- tags:
- - Experiment
- description: Delete an Experiment Profiles for a Test
- operationId: deleteProfile
- parameters:
- - name: testId
- in: path
- description: Test ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: profileId
- in: path
- description: Experiment Profile ID
- required: true
- schema:
- format: int32
- type: integer
- example: 202
- responses:
- "204":
- description: No Content
- /api/run/autocomplete:
- get:
- tags:
- - Run
- operationId: autocomplete
- parameters:
- - name: query
- in: query
- required: true
- schema:
- type: string
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- type: string
- /api/run/bySchema:
- get:
- tags:
- - Run
- description: Retrieve a paginated list of Runs with available count for a given
- Schema URI
- operationId: listBySchema
- parameters:
- - name: uri
- in: query
- description: Schema URI
- required: true
- schema:
- type: string
- example: uri:my-schema:0.1
- - name: limit
- in: query
- description: limit the number of results
- schema:
- format: int32
- type: integer
- example: 20
- - name: page
- in: query
- description: filter by page number of a paginated list of Tests
- schema:
- format: int32
- type: integer
- example: 2
- - name: sort
- in: query
- description: Field name to sort results
- schema:
- type: string
- example: name
- - name: direction
- in: query
- description: Sort direction
- schema:
- $ref: '#/components/schemas/SortDirection'
- example: Ascending
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RunsSummary'
- /api/run/count:
- get:
- tags:
- - Run
- description: Run count summary for given Test ID
- operationId: runCount
- parameters:
- - name: testId
- in: query
- description: Test ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RunCount'
- /api/run/data:
- post:
- tags:
- - Run
- description: Upload a new Run
- operationId: addRunFromData
- parameters:
- - name: start
- in: query
- description: "start timestamp of run, or json path expression"
- required: true
- schema:
- type: string
- examples:
- scalar value:
- value: 2023-10-23T00:13:35Z
- json path:
- value: $.buildTimeStamp
- - name: stop
- in: query
- description: "stop timestamp of run, or json path expression"
- required: true
- schema:
- type: string
- examples:
- scalar value:
- value: 2023-10-23T00:13:35Z
- json path:
- value: $.buildTimeStamp
- - name: test
- in: query
- description: test name of ID
- required: true
- schema:
- type: string
- example: my-benchmark
- - name: owner
- in: query
- description: Name of the new owner
- schema:
- type: string
- example: perf-team
- - name: access
- in: query
- description: New Access level
- schema:
- $ref: '#/components/schemas/Access'
- example: 0
- - name: token
- in: query
- description: Horreum internal token. Incompatible with Keycloak
- schema:
- type: string
- example: 094678029a2aaf9a2847502273099bb3a1b2338c2b9c618ed09aef0181666e38
- - name: schema
- in: query
- description: Schema URI
- schema:
- type: string
- example: uri:my-benchmark:0.2
- - name: description
- in: query
- description: Run description
- schema:
- type: string
- example: AWS runs
- requestBody:
- content:
- application/json:
- schema:
- type: string
- example:
- - tag: main
- score: 2031.7424089224041
- params:
- size: "1000"
- useTreeSet: "true"
- $schema: urn:jmh:0.2
- testName: org.drools.benchmarks.datastructures.QueueBenchmark.benchmark
- - $schema: urn:horreum:jenkins-plugin:0.1
- jobName: upstream-perf-bre-datastructures
- buildUrl: https://qe.com/job/TESTING/job/upstream-perfx-datastructures/125/
- startTime: 1698020160763
- uploadTime: 1698020592674
- buildNumber: 125
- jobFullName: TESTING/RHBA/_upstream/decisions/8.x/performance/nightly/upstream-perf-bre-datastructures
- scheduleTime: 1698020160756
- jobDisplayName: upstream-perf-bre-datastructures
- buildDisplayName: '#125'
- responses:
- "200":
- description: id of the newly generated run
- content:
- application/json:
- schema:
- format: int32
- type: integer
- example: 101
- "400":
- description: Some fields are missing or invalid
- content:
- application/json: {}
- /api/run/list:
- get:
- tags:
- - Run
- description: Retrieve a paginated list of Runs with available count
- operationId: listAllRuns
- parameters:
- - name: query
- in: query
- description: query string to filter runs
- schema:
- type: string
- - name: matchAll
- in: query
- description: match all Runs?
- schema:
- type: boolean
- example: false
- - name: roles
- in: query
- description: "__my, __all or a comma delimited list of roles"
- schema:
- type: string
- example: __my
- - name: trashed
- in: query
- description: show trashed runs
- schema:
- type: boolean
- example: false
- - name: limit
- in: query
- description: limit the number of results
- schema:
- format: int32
- type: integer
- example: 20
- - name: page
- in: query
- description: filter by page number of a paginated list of Tests
- schema:
- format: int32
- type: integer
- example: 2
- - name: sort
- in: query
- description: Field name to sort results
- schema:
- type: string
- example: name
- - name: direction
- in: query
- description: Sort direction
- schema:
- $ref: '#/components/schemas/SortDirection'
- example: Ascending
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RunsSummary'
- /api/run/list/{testId}:
- get:
- tags:
- - Run
- description: Retrieve a paginated list of Runs with available count for a given
- Test ID
- operationId: listTestRuns
- parameters:
- - name: testId
- in: path
- description: Test ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: trashed
- in: query
- description: include trashed runs
- schema:
- type: boolean
- example: false
- - name: limit
- in: query
- description: limit the number of results
- schema:
- format: int32
- type: integer
- example: 20
- - name: page
- in: query
- description: filter by page number of a paginated list of Tests
- schema:
- format: int32
- type: integer
- example: 2
- - name: sort
- in: query
- description: Field name to sort results
- schema:
- type: string
- example: name
- - name: direction
- in: query
- description: Sort direction
- schema:
- $ref: '#/components/schemas/SortDirection'
- example: Ascending
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RunsSummary'
- /api/run/recalculateAll:
- post:
- tags:
- - Run
- description: Recalculate Datasets for Runs between two dates
- operationId: recalculateAll
- parameters:
- - name: from
- in: query
- description: start timestamp
- schema:
- type: string
- example: 1698013206000
- - name: to
- in: query
- description: end timestamp
- schema:
- type: string
- example: 1698013206000
- responses:
- "201":
- description: Created
- /api/run/test:
- post:
- tags:
- - Run
- description: Upload a new Run
- operationId: add
- parameters:
- - name: test
- in: query
- description: test name of ID
- schema:
- type: string
- example: my-benchmark
- - name: owner
- in: query
- description: Name of the new owner
- schema:
- type: string
- example: perf-team
- - name: access
- in: query
- description: New Access level
- schema:
- $ref: '#/components/schemas/Access'
- example: 0
- - name: token
- in: query
- description: API token
- schema:
- type: string
- example: 094678029a2aaf9a2847502273099bb3a1b2338c2b9c618ed09aef0181666e38
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Run'
- required: true
- responses:
- "200":
- description: OK
- /api/run/{id}:
- get:
- tags:
- - Run
- description: Get extended Run information by Run ID
- operationId: getRun
- parameters:
- - name: id
- in: path
- description: Run ID
- required: true
- schema:
- format: int32
- type: integer
- example: 202
- - name: token
- in: query
- description: Run API token
- schema:
- type: string
- example: 094678029a2aaf9a2847502273099bb3a1b2338c2b9c618ed09aef0181666e38
- responses:
- "404":
- description: If no Run have been found with the given id
- content:
- application/json: {}
- "200":
- description: Run data with the referenced schemas and generated datasets
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RunExtended'
- /api/run/{id}/data:
- get:
- tags:
- - Run
- description: Get Run data by Run ID
- operationId: getData
- parameters:
- - name: id
- in: path
- description: Run ID
- required: true
- schema:
- format: int32
- type: integer
- example: 202
- - name: token
- in: query
- description: Run API token
- schema:
- type: string
- example: 094678029a2aaf9a2847502273099bb3a1b2338c2b9c618ed09aef0181666e38
- - name: schemaUri
- in: query
- description: FIlter by Schmea URI
- schema:
- type: string
- example: uri:my-benchmark:0.1
- responses:
- "200":
- description: Run payload
- content:
- application/json:
- schema:
- type: object
- example: "{ \"buildID\": 1709, ...}"
- /api/run/{id}/description:
- post:
- tags:
- - Run
- description: Update Run description
- operationId: updateDescription
- parameters:
- - name: id
- in: path
- description: Run ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- requestBody:
- content:
- text/plain:
- schema:
- type: string
- required: true
- responses:
- "201":
- description: Created
- /api/run/{id}/dropToken:
- post:
- tags:
- - Run
- description: Remove access token for Run
- operationId: dropToken
- parameters:
- - name: id
- in: path
- description: Token ID
- required: true
- schema:
- format: int32
- type: integer
- example: 102
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: string
- /api/run/{id}/labelValues:
- get:
- tags:
- - Run
- description: Get all the label values for the run
- operationId: labelValues
- parameters:
- - name: id
- in: path
- description: Run Id
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: filter
- in: query
- description: either a required json sub-document or path expression
- schema:
- default: "{}"
- type: string
- examples:
- object:
- description: json object that must exist in the values object
- value: "{labelName:necessaryValue,...}"
- string:
- description: valid filtering jsonpath that returns null if not found (not
- predicates)
- value: $.count ? (@ < 20 && @ > 10)
- - name: sort
- in: query
- description: label name for sorting
- schema:
- default: ""
- type: string
- - name: direction
- in: query
- description: either Ascending or Descending
- schema:
- default: Ascending
- type: string
- example: count
- - name: limit
- in: query
- description: the maximum number of results to include
- schema:
- format: int32
- default: 2147483647
- type: integer
- example: 10
- - name: page
- in: query
- description: which page to skip to when using a limit
- schema:
- format: int32
- default: 0
- type: integer
- example: 2
- responses:
- "200":
- description: label Values
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/ExportedLabelValues'
- example: "[ { \"datasetId\" : 101, \"runId\": 201, \"values\" : { [labelName]\
- \ : labelValue } },...]"
- /api/run/{id}/metadata:
- get:
- tags:
- - Run
- description: Get Run meta data by Run ID
- operationId: getMetadata
- parameters:
- - name: id
- in: path
- description: Run ID
- required: true
- schema:
- format: int32
- type: integer
- example: 202
- - name: token
- in: query
- description: Run API token
- schema:
- type: string
- example: 094678029a2aaf9a2847502273099bb3a1b2338c2b9c618ed09aef0181666e38
- - name: schemaUri
- in: query
- description: Filter by Schmea URI
- schema:
- type: string
- example: uri:my-benchmark:0.1
- responses:
- "200":
- description: Run payload
- content:
- application/json:
- schema:
- type: object
- example: "{ \"metaDataID\": 1709, ...}"
- /api/run/{id}/recalculate:
- post:
- tags:
- - Run
- description: Recalculate Datasets for Run
- operationId: recalculateDatasets
- parameters:
- - name: id
- in: path
- description: Run ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: Array of generated Datasets
- content:
- application/json:
- schema:
- type: array
- items:
- format: int32
- type: integer
- example:
- - 101
- - 102
- - 103
- /api/run/{id}/resetToken:
- post:
- tags:
- - Run
- description: Regenerate access token for Run
- operationId: resetToken
- parameters:
- - name: id
- in: path
- description: Token ID
- required: true
- schema:
- format: int32
- type: integer
- example: 102
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: string
- example: 094678029a2aaf9a2847502273099bb3a1b2338c2b9c618ed09aef0181666e38
- /api/run/{id}/schema:
- post:
- tags:
- - Run
- description: Update Run schema for part of JSON data
- operationId: updateSchema
- parameters:
- - name: id
- in: path
- description: Run ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: path
- in: query
- description: JSON path expression to update schema
- schema:
- type: string
- example: $.schemaURI
- requestBody:
- content:
- text/plain:
- schema:
- type: string
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: object
- additionalProperties:
- type: string
- /api/run/{id}/summary:
- get:
- tags:
- - Run
- description: Get Run Summary information by Run ID
- operationId: getRunSummary
- parameters:
- - name: id
- in: path
- description: Run ID
- required: true
- schema:
- format: int32
- type: integer
- example: 202
- - name: token
- in: query
- description: Run API token
- schema:
- type: string
- example: 094678029a2aaf9a2847502273099bb3a1b2338c2b9c618ed09aef0181666e38
- responses:
- "404":
- description: If no Run have been found with the given id
- content:
- application/json: {}
- "200":
- description: Run summary with the referenced schemas and generated datasets
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RunSummary'
- /api/run/{id}/trash:
- post:
- tags:
- - Run
- description: Trash a Run with a given ID
- operationId: trash
- parameters:
- - name: id
- in: path
- description: Run ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: isTrashed
- in: query
- description: should run be trashed?
- schema:
- type: boolean
- example: true
- responses:
- "201":
- description: Created
- /api/run/{id}/updateAccess:
- post:
- tags:
- - Run
- description: Update the Access configuration for a Run
- operationId: updateAccess
- parameters:
- - name: id
- in: path
- description: Run ID to update Access
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: owner
- in: query
- description: Name of the new owner
- required: true
- schema:
- type: string
- example: perf-team
- - name: access
- in: query
- description: New Access level
- required: true
- schema:
- $ref: '#/components/schemas/Access'
- example: 0
- responses:
- "201":
- description: Created
- /api/schema:
- get:
- tags:
- - Schema
- description: Retrieve a paginated list of Schemas with available count
- operationId: list
- parameters:
- - name: limit
- in: query
- description: limit the number of results
- schema:
- format: int32
- type: integer
- example: 20
- - name: page
- in: query
- description: filter by page number of a paginated list of Schemas
- schema:
- format: int32
- type: integer
- example: 2
- - name: sort
- in: query
- description: Field name to sort results
- schema:
- type: string
- example: name
- - name: direction
- in: query
- description: Sort direction
- schema:
- $ref: '#/components/schemas/SortDirection'
- example: Ascending
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/SchemaQueryResult'
- post:
- tags:
- - Schema
- description: Save a new Schema
- operationId: add
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Schema'
- responses:
- "200":
- description: Import a new Schema
- content:
- application/json:
- schema:
- format: int32
- type: integer
- example: 103
- /api/schema/allLabels:
- get:
- tags:
- - Schema
- description: Retrieve list of Labels for ny name. Allows users to retrieve all
- Label Definitions that have the same name
- operationId: allLabels
- parameters:
- - name: name
- in: query
- description: Label name
- schema:
- type: string
- example: buildID
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/LabelInfo'
- /api/schema/allTransformers:
- get:
- tags:
- - Schema
- description: Retrieve all transformers
- operationId: allTransformers
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/TransformerInfo'
- /api/schema/descriptors:
- get:
- tags:
- - Schema
- description: Retrieve a list of Schema Descriptors
- operationId: descriptors
- parameters:
- - name: id
- in: query
- description: Limit to a single Schema by ID
- schema:
- type: array
- items:
- format: int32
- type: integer
- example: 102
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/SchemaDescriptor'
- /api/schema/findUsages:
- get:
- tags:
- - Schema
- description: Find all usages of a Schema by label name
- operationId: findUsages
- parameters:
- - name: label
- in: query
- description: Name of label to search for
- required: true
- schema:
- type: string
- example: Throughput
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/LabelLocation'
- /api/schema/idByUri/{uri}:
- get:
- tags:
- - Schema
- description: Retrieve Schema ID by uri
- operationId: idByUri
- parameters:
- - name: uri
- in: path
- description: Schema uri
- required: true
- schema:
- type: string
- example: uri:my-schema:0.1
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- format: int32
- type: integer
- example: 101
- /api/schema/import:
- post:
- tags:
- - Schema
- description: Import an previously exported Schema either as a new Schema or
- to update an existing Schema
- operationId: importSchema
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/SchemaExport'
- required: true
- responses:
- "201":
- description: Import a new Schema or update an existing Schema
- /api/schema/{id}:
- get:
- tags:
- - Schema
- description: Retrieve Schema by ID
- operationId: getSchema
- parameters:
- - name: id
- in: path
- description: Schema ID to retrieve
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: token
- in: query
- description: API token for authorization
- schema:
- type: string
- example: 101
- responses:
- "404":
- description: No Schema with the given id was found
- content:
- application/json: {}
- "200":
- description: Returns Schema if a matching id is found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Schema'
- delete:
- tags:
- - Schema
- description: Delete a Schema by id
- operationId: delete
- parameters:
- - name: id
- in: path
- description: Schema ID to delete
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "204":
- description: No Content
- /api/schema/{id}/dropToken:
- delete:
- tags:
- - Schema
- description: Remove access token for schema
- operationId: dropToken
- parameters:
- - name: id
- in: path
- description: Token ID
- required: true
- schema:
- format: int32
- type: integer
- example: 102
- responses:
- "204":
- description: No Content
- /api/schema/{id}/export:
- get:
- tags:
- - Schema
- description: Export a Schema
- operationId: exportSchema
- parameters:
- - name: id
- in: path
- description: Schema ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: A JSON representation of the SchemaExport object
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/SchemaExport'
- /api/schema/{id}/resetToken:
- post:
- tags:
- - Schema
- description: Regenerate access token for schema
- operationId: resetToken
- parameters:
- - name: id
- in: path
- description: Token ID
- required: true
- schema:
- format: int32
- type: integer
- example: 102
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: string
- example: 094678029a2aaf9a2847502273099bb3a1b2338c2b9c618ed09aef0181666e38
- /api/schema/{id}/updateAccess:
- post:
- tags:
- - Schema
- description: Update the Access configuration for a Schema
- operationId: updateAccess
- parameters:
- - name: id
- in: path
- description: Schema ID to update Access
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: owner
- in: query
- description: Name of the new owner
- required: true
- schema:
- type: string
- example: perf-team
- - name: access
- in: query
- description: New Access level
- required: true
- schema:
- $ref: '#/components/schemas/Access'
- example: 0
- responses:
- "201":
- description: Created
- /api/schema/{schemaId}/labels:
- get:
- tags:
- - Schema
- description: Retrieve list of Labels for a Schema by Schema ID
- operationId: labels
- parameters:
- - name: schemaId
- in: path
- description: Schema ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/Label'
- post:
- tags:
- - Schema
- description: Save new or update existing Label for a Schema
- operationId: addOrUpdateLabel
- parameters:
- - name: schemaId
- in: path
- description: Schema ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Label'
- required: true
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- format: int32
- type: integer
- /api/schema/{schemaId}/labels/{labelId}:
- delete:
- tags:
- - Schema
- description: Delete existing Label from a Schema
- operationId: deleteLabel
- parameters:
- - name: schemaId
- in: path
- description: Schema ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: labelId
- in: path
- description: Label ID
- required: true
- schema:
- format: int32
- type: integer
- example: 202
- responses:
- "204":
- description: No Content
- /api/schema/{schemaId}/transformers:
- get:
- tags:
- - Schema
- description: List all Transformers defined for a Schema
- operationId: listTransformers
- parameters:
- - name: schemaId
- in: path
- description: Schema ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/Transformer'
- post:
- tags:
- - Schema
- description: Save new or update existing Transformer defintion
- operationId: addOrUpdateTransformer
- parameters:
- - name: schemaId
- in: path
- description: Schema ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Transformer'
- required: true
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- format: int32
- type: integer
- /api/schema/{schemaId}/transformers/{transformerId}:
- delete:
- tags:
- - Schema
- description: Delete a Transformer defined for a Schema
- operationId: deleteTransformer
- parameters:
- - name: schemaId
- in: path
- description: Schema ID
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: transformerId
- in: path
- description: Transformer ID
- required: true
- schema:
- format: int32
- type: integer
- example: 202
- responses:
- "204":
- description: No Content
- /api/test:
- get:
- tags:
- - Test
- description: Retrieve a paginated list of Tests with available count
- operationId: list
- parameters:
- - name: roles
- in: query
- description: "__my, __all or a comma delimited list of roles"
- schema:
- type: string
- example: __my
- - name: limit
- in: query
- description: limit the number of results
- schema:
- format: int32
- type: integer
- example: 20
- - name: page
- in: query
- description: filter by page number of a paginated list of Tests
- schema:
- format: int32
- type: integer
- example: 2
- - name: sort
- in: query
- description: Field name to sort results
- schema:
- default: name
- type: string
- example: name
- - name: direction
- in: query
- description: Sort direction
- schema:
- $ref: '#/components/schemas/SortDirection'
- example: Ascending
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/TestQueryResult'
- post:
- tags:
- - Test
- description: Create a new test
- operationId: add
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Test'
- required: true
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Test'
- /api/test/byName/{name}:
- get:
- tags:
- - Test
- description: Retrieve a test by name
- operationId: getByNameOrId
- parameters:
- - name: name
- in: path
- description: Name of test to retrieve
- required: true
- schema:
- type: string
- example: my-comprehensive-benchmark
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Test'
- /api/test/folders:
- get:
- tags:
- - Test
- description: Retrieve a list of all folders
- operationId: folders
- parameters:
- - name: roles
- in: query
- description: "\"__my\", \"__all\" or a comma delimited list of roles"
- schema:
- type: string
- example: __my
- responses:
- "200":
- description: List of all folders
- content:
- application/json:
- schema:
- type: array
- items:
- type: string
- example:
- - quarkus
- - ocp-perf-team
- /api/test/import:
- post:
- tags:
- - Test
- description: Import a previously exported Test either as a new Test or to update
- an existing Test
- operationId: importTest
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/TestExport'
- required: true
- responses:
- "201":
- description: Import a new Test or update an existing Test
- /api/test/summary:
- get:
- tags:
- - Test
- description: Retrieve a summary of Tests in a folder
- operationId: summary
- parameters:
- - name: roles
- in: query
- description: "\"__my\", \"__all\" or a comma delimited list of roles"
- schema:
- type: string
- example: __my
- - name: folder
- in: query
- description: name of the Folder containing the Tests
- schema:
- type: string
- example: My Team Folder
- - name: limit
- in: query
- description: limit the result count
- schema:
- default: 20
- type: integer
- example: 20
- - name: page
- in: query
- description: 'filter by page number of a paginated list of '
- schema:
- default: 1
- type: integer
- example: 1
- - name: direction
- in: query
- description: Sort direction
- schema:
- allOf:
- - $ref: '#/components/schemas/SortDirection'
- - default: Ascending
- example: Ascending
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/TestListing'
- /api/test/{id}:
- get:
- tags:
- - Test
- description: Retrieve a test by id
- operationId: get
- parameters:
- - name: id
- in: path
- required: true
- schema:
- format: int32
- type: integer
- - name: token
- in: query
- schema:
- type: string
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Test'
- delete:
- tags:
- - Test
- description: Delete a Test by id
- operationId: delete
- parameters:
- - name: id
- in: path
- required: true
- schema:
- format: int32
- type: integer
- responses:
- "204":
- description: No Content
- /api/test/{id}/addToken:
- post:
- tags:
- - Test
- description: "Add a Test API Token for access to provide access to a test data\
- \ for integrated tooling, e.g. reporting services"
- operationId: addToken
- parameters:
- - name: id
- in: path
- description: ID of test to add token to
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/TestToken'
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- format: int32
- type: integer
- /api/test/{id}/export:
- get:
- tags:
- - Test
- operationId: export
- parameters:
- - name: id
- in: path
- required: true
- schema:
- format: int32
- type: integer
- responses:
- "200":
- description: A Test definition formatted as json
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/TestExport'
- /api/test/{id}/fingerprint:
- get:
- tags:
- - Test
- description: List all Fingerprints for a Test
- operationId: listFingerprints
- parameters:
- - name: id
- in: path
- description: Test ID to retrieve Fingerprints for
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/Fingerprints'
- /api/test/{id}/labelValues:
- get:
- tags:
- - Test
- description: List all Label Values for a Test
- operationId: listLabelValues
- parameters:
- - name: id
- in: path
- description: Test ID to retrieve Label Values for
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: filtering
- in: query
- description: Retrieve values for Filtering Labels
- schema:
- default: true
- type: boolean
- example: true
- - name: metrics
- in: query
- description: Retrieve values for Metric Labels
- schema:
- default: true
- type: boolean
- example: false
- - name: filter
- in: query
- description: either a required json sub-document or path expression
- schema:
- default: "{}"
- type: string
- examples:
- object:
- description: json object that must exist in the values object
- value: "{labelName:necessaryValue,...}"
- string:
- description: valid filtering jsonpath that returns null if not found (not
- predicates)
- value: $.count ? (@ < 20 && @ > 10)
- - name: before
- in: query
- description: ISO-like date time string or epoch millis
- schema:
- default: ""
- type: string
- example: 1970-01-01T00:00:00+00:00 or an integer
- - name: after
- in: query
- description: ISO-like date time string or epoch millis
- schema:
- default: ""
- type: string
- example: 1970-01-01T00:00:00+00:00 or an integer
- - name: sort
- in: query
- description: json path to sortable value or start or stop for sorting by time
- schema:
- default: ""
- type: string
- example: $.label or start or stop
- - name: direction
- in: query
- description: either Ascending or Descending
- schema:
- default: Ascending
- type: string
- example: count
- - name: limit
- in: query
- description: the maximum number of results to include
- schema:
- format: int32
- default: 2147483647
- type: integer
- example: 10
- - name: page
- in: query
- description: which page to skip to when using a limit
- schema:
- format: int32
- default: 0
- type: integer
- example: 2
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/ExportedLabelValues'
- /api/test/{id}/move:
- post:
- tags:
- - Test
- description: Update the folder for a Test. Tests can be moved to different folders
- operationId: updateFolder
- parameters:
- - name: id
- in: path
- description: Test ID to update
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: folder
- in: query
- description: New folder to store the tests
- schema:
- type: string
- example: My Benchmark Folder
- responses:
- "201":
- description: Created
- /api/test/{id}/notifications:
- post:
- tags:
- - Test
- description: "Update notifications for a Test. It is possible to disable notifications\
- \ for a Test, so that no notifications are sent to subscribers"
- operationId: updateNotifications
- parameters:
- - name: id
- in: path
- description: Test ID to update
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: enabled
- in: query
- description: Whether notifications are enabled
- required: true
- schema:
- type: boolean
- example: false
- responses:
- "201":
- description: Created
- /api/test/{id}/recalculate:
- get:
- tags:
- - Test
- description: Get recalculation status for Test
- operationId: getRecalculationStatus
- parameters:
- - name: id
- in: path
- description: Test ID to retrieve recalculation status for
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RecalculationStatus'
- post:
- tags:
- - Test
- description: Recalculate Datasets for Test
- operationId: recalculateDatasets
- parameters:
- - name: id
- in: path
- description: Test ID to recalculate datasets for
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "201":
- description: Created
- /api/test/{id}/revokeToken/{tokenId}:
- delete:
- tags:
- - Test
- description: Revoke a Token defined for a Test
- operationId: dropToken
- parameters:
- - name: id
- in: path
- description: Test ID to revoke token
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: tokenId
- in: path
- description: ID of token to revoke
- required: true
- schema:
- format: int32
- type: integer
- example: 202
- responses:
- "204":
- description: No Content
- /api/test/{id}/tokens:
- get:
- tags:
- - Test
- description: A collection of Test Tokens for a given Test
- operationId: tokens
- parameters:
- - name: id
- in: path
- description: ID of test to retrieve list of tokens
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/TestToken'
- /api/test/{id}/transformers:
- post:
- tags:
- - Test
- description: Update transformers for Test
- operationId: updateTransformers
- parameters:
- - name: id
- in: path
- description: Test ID to retrieve Label Values for
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- requestBody:
- content:
- application/json:
- schema:
- type: array
- items:
- format: int32
- type: integer
- required: true
- responses:
- "201":
- description: Created
- /api/test/{id}/updateAccess:
- post:
- tags:
- - Test
- description: Update the Access configuration for a Test
- operationId: updateAccess
- parameters:
- - name: id
- in: path
- description: Test ID to revoke token
- required: true
- schema:
- format: int32
- type: integer
- example: 101
- - name: owner
- in: query
- description: Name of the new owner
- required: true
- schema:
- type: string
- example: perf-team
- - name: access
- in: query
- description: New Access level for the Test
- required: true
- schema:
- $ref: '#/components/schemas/Access'
- example: 0
- responses:
- "201":
- description: Created
-components:
- schemas:
- Access:
- description: "Resources have different visibility within the UI. 'PUBLIC', 'PROTECTED'\
- \ and 'PRIVATE'. Restricted resources are not visible to users who do not\
- \ have the correct permissions"
- enum:
- - PUBLIC
- - PROTECTED
- - PRIVATE
- type: string
- Action:
- required:
- - id
- - event
- - type
- - config
- - secrets
- - testId
- - active
- - runAlways
- type: object
- properties:
- id:
- format: int32
- type: integer
- event:
- type: string
- type:
- type: string
- config:
- type: object
- oneOf:
- - $ref: '#/components/schemas/HttpAction'
- - $ref: '#/components/schemas/GithubIssueCommentAction'
- - $ref: '#/components/schemas/GithubIssueCreateAction'
- secrets:
- type: object
- allOf:
- - $ref: '#/components/schemas/Secret'
- testId:
- format: int32
- type: integer
- active:
- type: boolean
- runAlways:
- type: boolean
- ActionLog:
- description: Action Log
- required:
- - testId
- - event
- type: object
- allOf:
- - $ref: '#/components/schemas/PersistentLog'
- properties:
- testId:
- format: int32
- type: integer
- event:
- type: string
- type:
- type: string
- BetterOrWorse:
- description: Result of running an Experiment
- enum:
- - BETTER
- - SAME
- - WORSE
- type: string
- ChangeDetection:
- required:
- - id
- - model
- - config
- type: object
- properties:
- id:
- format: int32
- type: integer
- model:
- type: string
- config:
- type: object
- oneOf:
- - $ref: '#/components/schemas/RelativeDifferenceDetectionConfig'
- - $ref: '#/components/schemas/FixedThresholdDetectionConfig'
- discriminator:
- propertyName: model
- mapping:
- relativeDifference: '#/components/schemas/RelativeDifferenceDetectionConfig'
- fixedThreshold: '#/components/schemas/FixedThresholdDetectionConfig'
- ChangeDetectionModelType:
- description: Type of Change Detection Model
- enum:
- - FIXED_THRESHOLD
- - RELATIVE_DIFFERENCE
- type: string
- ComparisonResult:
- description: Result of performing a Comparison
- type: object
- properties:
- overall:
- description: Was the Experiment dataset better or worse than the baseline
- dataset
- enum:
- - BETTER
- - SAME
- - WORSE
- type: string
- allOf:
- - $ref: '#/components/schemas/BetterOrWorse'
- experimentValue:
- format: double
- description: Experiment value
- type: number
- baselineValue:
- format: double
- description: Baseline value
- type: number
- result:
- description: The relative difference between the Experiment and Baseline
- Datasets
- type: string
- ConditionComponent:
- required:
- - name
- - title
- - description
- - type
- - properties
- type: object
- properties:
- name:
- description: Change detection model component name
- type: string
- example: min
- title:
- description: Change detection model component title
- type: string
- example: Minimum
- description:
- description: Change detection model component description
- type: string
- example: Lower bound for acceptable datapoint values.
- type:
- description: UI Component type
- enum:
- - LOG_SLIDER
- - ENUM
- - NUMBER_BOUND
- - SWITCH
- type: object
- example: '"LOG_SLIDER"'
- properties:
- description: Map of properties for component
- type: object
- additionalProperties: {}
- example: ""
- ConditionConfig:
- description: A configuration object for Change detection models
- required:
- - name
- - title
- - description
- - ui
- type: object
- properties:
- name:
- description: Name of Change detection model
- type: string
- example: fixedThreshold
- title:
- description: UI name for change detection model
- type: string
- example: Fixed Threshold
- description:
- description: Change detection model description
- type: string
- example: This model checks that the datapoint value is within fixed bounds.
- ui:
- description: A list of UI components for dynamically building the UI components
- type: array
- items:
- $ref: '#/components/schemas/ConditionComponent'
- defaults:
- description: A dictionary of UI default configuration items for dynamically
- building the UI components
- type: object
- additionalProperties: {}
- Dataset:
- description: A dataset is the JSON document used as the basis for all comparisons
- and reporting
- required:
- - testid
- - data
- - ordinal
- type: object
- allOf:
- - $ref: '#/components/schemas/ProtectedType'
- - $ref: '#/components/schemas/ProtectedTimeType'
- properties:
- id:
- format: int32
- description: Dataset Unique ID
- type: integer
- example: 101
- description:
- description: Run description
- type: string
- example: Run on AWS with m7g.large
- testid:
- format: int32
- description: Test ID that Dataset relates to
- type: integer
- example: 101
- data:
- description: Data payload
- type: string
- ordinal:
- format: int32
- description: Dataset ordinal for ordered list of Datasets derived from a
- Run
- type: integer
- example: 1
- validationErrors:
- description: List of Validation Errors
- type: array
- items:
- $ref: '#/components/schemas/ValidationError'
- runId:
- format: int32
- description: Run ID that Dataset relates to
- type: integer
- example: 101
- DatasetInfo:
- required:
- - id
- - runId
- - ordinal
- - testId
- type: object
- properties:
- id:
- format: int32
- description: Dataset ID for Dataset
- type: integer
- example: 101
- runId:
- format: int32
- description: Run ID that Dataset relates to
- type: integer
- example: 101
- ordinal:
- format: int32
- description: Ordinal position in ordered list
- type: integer
- example: 2
- testId:
- format: int32
- description: Test ID that Dataset relates to
- type: integer
- example: 103
- DatasetList:
- description: Result containing a subset of Dataset Summaries and the total count
- of available. Used in paginated tables
- required:
- - total
- - datasets
- type: object
- properties:
- total:
- format: int64
- description: Total number of Dataset Summaries available
- type: integer
- example: 64
- datasets:
- description: List of Dataset Summaries. This is often a subset of total
- available.
- type: array
- items:
- $ref: '#/components/schemas/DatasetSummary'
- DatasetLog:
- description: Dataset Log
- required:
- - source
- - testId
- - runId
- - datasetId
- - datasetOrdinal
- type: object
- allOf:
- - $ref: '#/components/schemas/PersistentLog'
- properties:
- source:
- type: string
- testId:
- format: int32
- type: integer
- runId:
- format: int32
- type: integer
- datasetId:
- format: int32
- type: integer
- datasetOrdinal:
- format: int32
- type: integer
- DatasetSummary:
- required:
- - id
- - runId
- - ordinal
- - testId
- - testname
- - schemas
- type: object
- allOf:
- - $ref: '#/components/schemas/ProtectedTimeType'
- properties:
- id:
- format: int32
- description: Unique Dataset ID
- type: integer
- example: 101
- runId:
- format: int32
- description: Run ID that Dataset relates to
- type: integer
- example: 202
- ordinal:
- format: int32
- description: Ordinal position of Dataset Summary on returned List
- type: integer
- example: 3
- testId:
- format: int32
- description: Test ID that Dataset relates to
- type: integer
- example: 202
- testname:
- description: Test name that the Dataset relates to
- type: string
- example: my-comprehensive-benchmark
- description:
- description: Dataset description
- type: string
- example: Run on AWS with m7g.large
- view:
- description: map of view component ids to the LabelValueMap to render the
- component for this dataset
- type: object
- allOf:
- - $ref: '#/components/schemas/IndexedLabelValueMap'
- example: "{ \"[view_component_id]\": { \"[labelName]\": labelValue} }"
- schemas:
- description: List of Schema usages
- type: array
- items:
- $ref: '#/components/schemas/SchemaUsage'
- validationErrors:
- description: List of Validation Errors
- type: array
- items:
- $ref: '#/components/schemas/ValidationError'
- Datastore:
- description: Type of backend datastore
- required:
- - access
- - owner
- - id
- - name
- - builtIn
- - config
- - type
- type: object
- properties:
- access:
- description: Access rights for the test. This defines the visibility of
- the Test in the UI
- enum:
- - PUBLIC
- - PROTECTED
- - PRIVATE
- type: string
- allOf:
- - $ref: '#/components/schemas/Access'
- example: PUBLIC
- owner:
- description: Name of the team that owns the test. Users must belong to the
- team that owns a test to make modifications
- type: string
- example: performance-team
- id:
- format: int32
- description: Unique Datastore id
- type: integer
- example: 101
- name:
- description: "Name of the datastore, used to identify the datastore in the\
- \ Test definition"
- type: string
- example: Perf Elasticsearch
- builtIn:
- description: Is this a built-in datastore? Built-in datastores cannot be
- deleted or modified
- type: boolean
- example: false
- config:
- type: object
- oneOf:
- - $ref: '#/components/schemas/ElasticsearchDatastoreConfig'
- - $ref: '#/components/schemas/PostgresDatastoreConfig'
- type:
- description: Type of backend datastore
- enum:
- - POSTGRES
- - ELASTICSEARCH
- type: string
- example: ELASTICSEARCH
- DatastoreTestResponse:
- type: object
- properties:
- msg:
- type: string
- success:
- type: boolean
- DatastoreType:
- description: Type of backend datastore
- enum:
- - POSTGRES
- - ELASTICSEARCH
- type: string
- example: ELASTICSEARCH
- ElasticsearchDatastoreConfig:
- description: Type of backend datastore
- required:
- - builtIn
- - url
- type: object
- properties:
- builtIn:
- description: Built In
- type: boolean
- apiKey:
- description: Elasticsearch API KEY
- type: string
- url:
- description: Elasticsearch url
- type: string
- username:
- description: Elasticsearch username
- type: string
- password:
- description: Elasticsearch password
- type: string
- ErrorDetails:
- required:
- - type
- - message
- type: object
- properties:
- type:
- description: Validation Error type
- type: string
- code:
- type: string
- path:
- type: string
- evaluationPath:
- type: string
- schemaPath:
- type: string
- deprecated: true
- schemaLocation:
- type: string
- instanceLocation:
- type: string
- property:
- type: string
- arguments:
- type: array
- items:
- type: string
- details:
- type: string
- messageKey:
- type: string
- valid:
- type: boolean
- message:
- type: string
- ExperimentComparison:
- required:
- - model
- - config
- - variableId
- type: object
- properties:
- model:
- description: Name of comparison model
- type: string
- example: relativeDifference
- config:
- description: Model JSON configuration
- type: string
- variableId:
- format: int32
- description: Variable ID to run experiment against
- type: integer
- example: 101
- variableName:
- description: Variable Name to run experiment against
- type: string
- example: Throughput
- ExperimentProfile:
- description: An Experiment Profile defines the labels and filters for the dataset
- and baseline
- required:
- - id
- - name
- - selectorLabels
- - baselineLabels
- - comparisons
- type: object
- properties:
- id:
- format: int32
- description: Experiment Profile unique ID
- type: integer
- example: 101
- name:
- description: Name of Experiment Profile
- type: string
- example: Techempower comparison
- testId:
- format: int32
- description: Test ID that Experiment Profile relates to
- type: integer
- example: 101
- selectorLabels:
- description: Array of selector labels
- type: array
- items:
- type: string
- example:
- - Framework
- selectorFilter:
- description: Selector filter to apply to Selector label values
- type: string
- example: value => value === 'quarkus-resteasy-reactive-hibernate-reactive'
- baselineLabels:
- description: Array of selector labels for comparison Baseline
- type: array
- items:
- type: string
- example:
- - timestamp
- baselineFilter:
- description: Selector filter to apply to Baseline label values
- type: string
- example: value => value === 1666955225547
- comparisons:
- description: Collection of Experiment Comparisons to run during an Experiment
- evaluation
- type: array
- items:
- $ref: '#/components/schemas/ExperimentComparison'
- extraLabels:
- description: These labels are not used by Horreum but are added to the result
- event and therefore can be used e.g. when firing an Action.
- type: array
- items:
- type: string
- ExperimentResult:
- description: Result of running an Experiment
- type: object
- properties:
- profile:
- description: Experiment profile that results relates to
- type: object
- allOf:
- - $ref: '#/components/schemas/ExperimentProfile'
- logs:
- description: A list of log statements recorded while Experiment was evaluated
- type: array
- items:
- $ref: '#/components/schemas/DatasetLog'
- datasetInfo:
- description: Dataset Info about dataset used for experiment
- type: object
- allOf:
- - $ref: '#/components/schemas/DatasetInfo'
- baseline:
- description: A list of Dataset Info for experiment baseline(s)
- type: array
- items:
- $ref: '#/components/schemas/DatasetInfo'
- results:
- description: A Map of all comparisons and results evaluated during an Experiment
- type: object
- additionalProperties:
- $ref: '#/components/schemas/ComparisonResult'
- extraLabels:
- type: string
- notify:
- type: boolean
- ExportedLabelValues:
- description: A map of label names to label values with the associated datasetId
- and runId
- required:
- - start
- - stop
- type: object
- properties:
- values:
- $ref: '#/components/schemas/LabelValueMap'
- runId:
- format: int32
- description: the run id that created the dataset
- type: integer
- example: 101
- datasetId:
- format: int32
- description: the unique dataset id
- type: integer
- example: 101
- start:
- format: date-time
- description: Start timestamp
- type: string
- example: 2019-09-26T07:58:30.996+0200
- stop:
- format: date-time
- description: Stop timestamp
- type: string
- example: 2019-09-26T07:58:30.996+0200
- Extractor:
- description: "An Extractor defines how values are extracted from a JSON document,\
- \ for use in Labels etc."
- required:
- - name
- - jsonpath
- - isarray
- type: object
- properties:
- name:
- description: Name of extractor. This name is used in Combination Functions
- to refer to values by name
- type: string
- example: buildID
- jsonpath:
- description: JSON path expression defining the location of the extractor
- value in the JSON document. This is a pSQL json path expression
- type: string
- example: $.buildInfo.buildID
- isarray:
- description: Does the JSON path expression reference an Array?
- type: boolean
- example: false
- FingerprintValue:
- description: Representation of Fingerprint. If the Fingerprint has children
- the value will be null.
- type: object
- properties:
- name:
- description: Fingerprint name
- type: string
- example: Mode
- value:
- description: Fingerprint name
- example: Library
- children:
- description: List of Fingerprint children
- type: array
- items:
- description: Cyclic reference to io.hyperfoil.tools.horreum.api.data.FingerprintValue
- Fingerprints:
- description: A list of Fingerprints representing one dataset
- type: object
- properties:
- values:
- type: array
- items:
- $ref: '#/components/schemas/FingerprintValue'
- FixThresholdConfig:
- required:
- - value
- - enabled
- - inclusive
- type: object
- properties:
- value:
- description: Threshold Value
- type: integer
- example: 95
- enabled:
- description: Threshold enabled/disabled
- type: boolean
- example: true
- inclusive:
- description: Is threshold inclusive of defined value?
- type: boolean
- example: false
- FixedThresholdDetectionConfig:
- required:
- - builtIn
- - min
- - max
- type: object
- properties:
- builtIn:
- description: Built In
- type: boolean
- min:
- description: Lower bound for acceptable datapoint values
- type: object
- allOf:
- - $ref: '#/components/schemas/FixThresholdConfig'
- max:
- description: Upper bound for acceptable datapoint values
- type: object
- allOf:
- - $ref: '#/components/schemas/FixThresholdConfig'
- GithubIssueCommentAction:
- type: object
- properties:
- issueUrl:
- type: string
- owner:
- type: string
- repo:
- type: string
- issue:
- type: string
- formatter:
- type: string
- GithubIssueCreateAction:
- type: object
- properties:
- owner:
- type: string
- repo:
- type: string
- title:
- type: string
- formatter:
- type: string
- HttpAction:
- type: object
- properties:
- url:
- type: string
- IndexedLabelValueMap:
- type: object
- additionalProperties:
- $ref: '#/components/schemas/LabelValueMap'
- KeycloakConfig:
- type: object
- properties:
- realm:
- description: Keycloak realm securing Horreum instance
- type: string
- example: horreum
- url:
- description: URL of Keycloak instance securing Horreum
- type: string
- example: https://horreum-keycloak.example.com
- clientId:
- description: Keycloak client ID in Horreum realm for User Interface
- type: string
- example: horreum-ui
- Label:
- description: "A Label is a core component of Horreum, defining which components\
- \ of the JSON document are part of a KPI and how the metric values are calculated"
- required:
- - id
- - name
- - extractors
- - filtering
- - metrics
- - schemaId
- type: object
- allOf:
- - $ref: '#/components/schemas/ProtectedType'
- properties:
- id:
- format: int32
- description: Unique ID for Label
- type: integer
- example: 101
- name:
- description: "Name for label. NOTE: all Labels are considered to have the\
- \ same semantic meaning throughout the entire system"
- type: string
- example: Throughput
- extractors:
- description: "A collection of Extractors, that will be combined in the Combination\
- \ Function"
- type: array
- items:
- $ref: '#/components/schemas/Extractor'
- function:
- description: A Combination Function that defines how values from Extractors
- are combined to produce a Label Value
- type: string
- example: "value => { return ((value.reduce((a,b) => a+b))/value.length*1000).toFixed(3);\
- \ }"
- filtering:
- description: Is Label a filtering label? Filtering labels contains values
- that are used to filter datasets for comparison
- type: boolean
- example: true
- metrics:
- description: Is Label a metrics label? Metrics labels are contain Metrics
- that are used for comparison
- type: boolean
- example: true
- schemaId:
- format: int32
- description: Schema ID that the Label relates to
- type: integer
- example: 101
- LabelInFingerprint:
- type: object
- allOf:
- - $ref: '#/components/schemas/LabelLocation'
- LabelInReport:
- type: object
- allOf:
- - $ref: '#/components/schemas/LabelLocation'
- properties:
- configId:
- format: int32
- type: integer
- title:
- type: string
- where:
- type: string
- name:
- type: string
- LabelInRule:
- type: object
- allOf:
- - $ref: '#/components/schemas/LabelLocation'
- properties:
- ruleId:
- format: int32
- type: integer
- ruleName:
- type: string
- LabelInVariable:
- type: object
- allOf:
- - $ref: '#/components/schemas/LabelLocation'
- properties:
- variableId:
- format: int32
- type: integer
- variableName:
- type: string
- LabelInView:
- type: object
- allOf:
- - $ref: '#/components/schemas/LabelLocation'
- properties:
- viewId:
- format: int32
- type: integer
- viewName:
- type: string
- componentId:
- format: int32
- type: integer
- header:
- type: string
- LabelInfo:
- required:
- - name
- - metrics
- - filtering
- - schemas
- type: object
- properties:
- name:
- description: Label name
- type: string
- example: buildID
- metrics:
- description: Is label a metrics label?
- type: boolean
- example: true
- filtering:
- description: Is label a filtering label?
- type: boolean
- example: false
- schemas:
- description: List of schemas where label is referenced
- type: array
- items:
- $ref: '#/components/schemas/SchemaDescriptor'
- LabelLocation:
- type: object
- properties:
- type:
- description: Location of Label usage
- type: string
- example: VIEW
- testId:
- format: int32
- description: Unique ID for location that references Schema
- type: integer
- example: 101
- testName:
- description: Test name that references Schema
- type: string
- example: My Benchmark
- LabelPreview:
- description: Preview a Label Value derived from a Dataset Data. A preview allows
- users to apply a Label to a dataset and preview the Label Value result and
- processing errors in the UI
- type: object
- properties:
- value:
- description: "Value value extracted from Dataset. This can be a scalar,\
- \ array or JSON object"
- type: string
- output:
- description: Description of errors occurred attempting to generate Label
- Value Preview
- type: string
- LabelValue:
- description: Label Value derived from Label definition and Dataset Data
- required:
- - id
- - name
- - schema
- type: object
- properties:
- id:
- format: int32
- description: Unique ID for Label Value
- type: integer
- example: 101
- name:
- description: Label name
- type: string
- example: buildID
- schema:
- description: Summary description of Schema
- type: object
- allOf:
- - $ref: '#/components/schemas/SchemaDescriptor'
- value:
- description: "Value value extracted from Dataset. This can be a scalar,\
- \ array or JSON object"
- type: string
- example: "1724"
- LabelValueMap:
- description: a map of label name to value
- type: object
- example: "{ \"[labelName]\": labelValue}"
- MissingDataRule:
- required:
- - id
- - maxStaleness
- - testId
- type: object
- properties:
- id:
- format: int32
- type: integer
- name:
- type: string
- labels:
- type: array
- items:
- type: string
- condition:
- type: string
- maxStaleness:
- format: int64
- type: integer
- lastNotification:
- format: date-time
- type: string
- example: 2022-03-10T16:15:50Z
- testId:
- format: int32
- type: integer
- PersistentLog:
- description: Persistent Log
- required:
- - id
- - level
- - timestamp
- - message
- type: object
- properties:
- id:
- format: int64
- type: integer
- level:
- format: int32
- type: integer
- timestamp:
- format: date-time
- type: string
- example: 2022-03-10T16:15:50Z
- message:
- type: string
- PostgresDatastoreConfig:
- description: Built in backend datastore
- required:
- - builtIn
- type: object
- properties:
- builtIn:
- description: Built In
- type: boolean
- ProtectedTimeType:
- required:
- - access
- - owner
- - start
- - stop
- type: object
- properties:
- access:
- description: Access rights for the test. This defines the visibility of
- the Test in the UI
- enum:
- - PUBLIC
- - PROTECTED
- - PRIVATE
- type: string
- allOf:
- - $ref: '#/components/schemas/Access'
- example: PUBLIC
- owner:
- description: Name of the team that owns the test. Users must belong to the
- team that owns a test to make modifications
- type: string
- example: performance-team
- start:
- format: int64
- description: Run Start timestamp
- type: integer
- example: 1704965908267
- stop:
- format: int64
- description: Run Stop timestamp
- type: integer
- example: 1704965908267
- ProtectedType:
- required:
- - access
- - owner
- type: object
- properties:
- access:
- description: Access rights for the test. This defines the visibility of
- the Test in the UI
- enum:
- - PUBLIC
- - PROTECTED
- - PRIVATE
- type: string
- allOf:
- - $ref: '#/components/schemas/Access'
- example: PUBLIC
- owner:
- description: Name of the team that owns the test. Users must belong to the
- team that owns a test to make modifications
- type: string
- example: performance-team
- RecalculationStatus:
- required:
- - timestamp
- - totalRuns
- - finished
- - datasets
- type: object
- properties:
- timestamp:
- format: int64
- description: Recalculation timestamp
- type: integer
- example: 1698013206000
- totalRuns:
- format: int64
- description: Total number of Runs being recalculated
- type: integer
- example: 152
- finished:
- format: int64
- description: Total number of completed recalculations
- type: integer
- example: 93
- datasets:
- format: int64
- description: Total number of generated datasets
- type: integer
- example: 186
- RelativeDifferenceDetectionConfig:
- required:
- - builtIn
- - filter
- - window
- - threshold
- - minPrevious
- type: object
- properties:
- builtIn:
- description: Built In
- type: boolean
- filter:
- description: Relative Difference Detection filter
- type: string
- example: mean
- window:
- format: int32
- description: Number of most recent datapoints used for aggregating the value
- for comparison.
- type: integer
- example: 5
- threshold:
- format: double
- description: Maximum difference between the aggregated value of last
- datapoints and the mean of preceding values.
- type: number
- example: 0.2
- minPrevious:
- format: int32
- description: Minimal number of preceding datapoints
- type: integer
- example: 5
- ReportComponent:
- description: Report Component
- required:
- - name
- - order
- - labels
- type: object
- properties:
- id:
- format: int32
- type: integer
- name:
- type: string
- order:
- format: int32
- type: integer
- labels:
- description: Array of labels
- type: array
- items:
- type: string
- example:
- - Framework
- function:
- type: string
- unit:
- type: string
- reportId:
- format: int32
- type: integer
- ReportLog:
- description: Report Log
- required:
- - reportId
- type: object
- allOf:
- - $ref: '#/components/schemas/PersistentLog'
- properties:
- reportId:
- format: int32
- type: integer
- Run:
- required:
- - access
- - owner
- - start
- - stop
- - id
- - testid
- - data
- - trashed
- type: object
- properties:
- access:
- description: Access rights for the test. This defines the visibility of
- the Test in the UI
- enum:
- - PUBLIC
- - PROTECTED
- - PRIVATE
- type: string
- allOf:
- - $ref: '#/components/schemas/Access'
- example: PUBLIC
- owner:
- description: Name of the team that owns the test. Users must belong to the
- team that owns a test to make modifications
- type: string
- example: performance-team
- start:
- format: int64
- description: Run Start timestamp
- type: integer
- example: 1704965908267
- stop:
- format: int64
- description: Run Stop timestamp
- type: integer
- example: 1704965908267
- id:
- format: int32
- description: Unique Run ID
- type: integer
- example: 101
- description:
- description: Run description
- type: string
- example: Run on AWS with m7g.large
- testid:
- format: int32
- description: Test ID run relates to
- type: integer
- example: 101
- data:
- description: Run result payload
- type: string
- metadata:
- description: "JSON metadata related to run, can be tool configuration etc"
- type: string
- trashed:
- description: Has Run been deleted from UI
- type: boolean
- example: false
- datasets:
- description: Collection of Datasets derived from Run payload
- type: array
- items:
- $ref: '#/components/schemas/Dataset'
- validationErrors:
- description: Collection of Validation Errors in Run payload
- type: array
- items:
- $ref: '#/components/schemas/ValidationError'
- RunCount:
- required:
- - total
- - active
- - trashed
- type: object
- properties:
- total:
- format: int64
- description: Total count of Runs visible
- type: integer
- example: 100
- active:
- format: int64
- description: Total count of active Runs visible
- type: integer
- example: 95
- trashed:
- format: int64
- description: Total count of trashed Runs
- type: integer
- example: 5
- RunExtended:
- required:
- - access
- - owner
- - start
- - stop
- - id
- - testid
- - data
- - trashed
- - schemas
- - testname
- - datasets
- type: object
- properties:
- access:
- description: Access rights for the test. This defines the visibility of
- the Test in the UI
- enum:
- - PUBLIC
- - PROTECTED
- - PRIVATE
- type: string
- allOf:
- - $ref: '#/components/schemas/Access'
- example: PUBLIC
- owner:
- description: Name of the team that owns the test. Users must belong to the
- team that owns a test to make modifications
- type: string
- example: performance-team
- start:
- format: int64
- description: Run Start timestamp
- type: integer
- example: 1704965908267
- stop:
- format: int64
- description: Run Stop timestamp
- type: integer
- example: 1704965908267
- id:
- format: int32
- description: Unique Run ID
- type: integer
- example: 101
- description:
- description: Run description
- type: string
- example: Run on AWS with m7g.large
- testid:
- format: int32
- description: Test ID run relates to
- type: integer
- example: 101
- data:
- description: Run result payload
- type: string
- metadata:
- description: "JSON metadata related to run, can be tool configuration etc"
- type: string
- trashed:
- description: Has Run been deleted from UI
- type: boolean
- example: false
- validationErrors:
- description: Collection of Validation Errors in Run payload
- type: array
- items:
- $ref: '#/components/schemas/ValidationError'
- schemas:
- description: List of Schema Usages
- type: array
- items:
- $ref: '#/components/schemas/SchemaUsage'
- testname:
- description: Test name run references
- type: string
- example: My benchmark
- datasets:
- description: List of DatasetIDs
- type: array
- items:
- format: int32
- type: integer
- example:
- - 101
- - 102
- - 104
- - 106
- RunSummary:
- required:
- - id
- - testid
- - testname
- - trashed
- - hasMetadata
- - datasets
- type: object
- allOf:
- - $ref: '#/components/schemas/ProtectedTimeType'
- properties:
- id:
- format: int32
- description: Run unique ID
- type: integer
- example: 202
- testid:
- format: int32
- description: test ID run relates to
- type: integer
- example: 101
- token:
- type: string
- testname:
- description: test ID run relates to
- type: string
- example: My benchmark
- trashed:
- description: has Run been trashed in the UI
- type: boolean
- example: false
- hasMetadata:
- description: does Run have metadata uploaded alongside Run data
- type: boolean
- example: false
- description:
- description: Run description
- type: string
- example: Run on AWS with m7g.large
- schemas:
- description: List of all Schema Usages for Run
- type: array
- items:
- $ref: '#/components/schemas/SchemaUsage'
- datasets:
- description: Array of datasets ids
- type: array
- items:
- format: int32
- type: integer
- example:
- - 101
- - 102
- - 103
- validationErrors:
- description: Array of validation errors
- type: array
- items:
- $ref: '#/components/schemas/ValidationError'
- RunsSummary:
- required:
- - total
- - runs
- type: object
- properties:
- total:
- format: int64
- description: Total count of Runs visible
- type: integer
- example: 1
- runs:
- description: List of Run Summaries
- type: array
- items:
- $ref: '#/components/schemas/RunSummary'
- Schema:
- description: Data object that describes the schema definition for a test
- required:
- - id
- - uri
- - name
- type: object
- allOf:
- - $ref: '#/components/schemas/ProtectedType'
- properties:
- id:
- format: int32
- description: Unique Schema ID
- type: integer
- example: 101
- uri:
- description: "Unique, versioned schema URI"
- type: string
- example: uri:my-schema:0.1
- name:
- description: Schema name
- type: string
- example: My benchmark schema
- description:
- description: Schema Description
- type: string
- example: Schema for processing my benchmark
- schema:
- description: JSON validation schema. Used to validate uploaded JSON documents
- type: string
- example: "{ \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\
- , \"$id\": \"https://example.com/product.schema.json\", \"title\": \"\
- Product\", \"description\": \"A product in the catalog\", \"type\":\
- \ \"object\"}"
- token:
- description: Array of API tokens associated with test
- type: string
- example: ""
- SchemaDescriptor:
- required:
- - id
- - name
- - uri
- type: object
- properties:
- id:
- format: int32
- description: Schema unique ID
- type: integer
- example: 1
- name:
- description: Schema name
- type: string
- example: my-benchmark-schema
- uri:
- description: Schema name
- type: string
- example: uri:my-schmea:0.1
- SchemaExport:
- description: Represents a Schema with all associated data used for export/import
- operations.
- type: object
- allOf:
- - $ref: '#/components/schemas/Schema'
- properties:
- labels:
- description: Array of Labels associated with schema
- type: array
- items:
- $ref: '#/components/schemas/Label'
- transformers:
- description: Array of Transformers associated with schema
- type: array
- items:
- $ref: '#/components/schemas/Transformer'
- SchemaQueryResult:
- required:
- - schemas
- - count
- type: object
- properties:
- schemas:
- description: Array of Schemas
- type: array
- items:
- $ref: '#/components/schemas/Schema'
- count:
- format: int64
- description: Count of available Schemas. This is a count of Schemas that
- the current user has access to
- type: integer
- example: 64
- SchemaUsage:
- required:
- - id
- - name
- - uri
- - source
- - type
- - hasJsonSchema
- type: object
- properties:
- id:
- format: int32
- description: Schema unique ID
- type: integer
- example: 1
- name:
- description: Schema name
- type: string
- example: my-benchmark-schema
- uri:
- description: Schema name
- type: string
- example: uri:my-schmea:0.1
- source:
- format: int32
- description: "Source of schema usage, 0 is data, 1 is metadata. DataSets\
- \ always use 0"
- type: integer
- example: 1
- type:
- format: int32
- description: "Location of Schema Usage, 0 for Run, 1 for Dataset"
- type: integer
- example: 1
- key:
- description: Ordinal position of schema usage in Run/Dataset
- type: string
- example: "1"
- hasJsonSchema:
- description: Does schema have a JSON validation schema defined?
- type: boolean
- example: false
- Secret:
- type: object
- properties:
- token:
- type: string
- modified:
- type: boolean
- SortDirection:
- enum:
- - Ascending
- - Descending
- type: string
- TableReport:
- description: Table Report
- required:
- - id
- - config
- - created
- - comments
- - data
- - logs
- type: object
- properties:
- id:
- format: int32
- type: integer
- config:
- description: Table Report Config
- required:
- - id
- - title
- - seriesLabels
- - components
- type: object
- allOf:
- - $ref: '#/components/schemas/TableReportConfig'
- properties:
- id:
- format: int32
- type: integer
- title:
- type: string
- test:
- $ref: '#/components/schemas/Test'
- filterLabels:
- description: ArrayNode of filter labels
- type: array
- items:
- type: string
- filterFunction:
- type: string
- categoryLabels:
- description: ArrayNode of category labels
- type: array
- items:
- type: string
- categoryFunction:
- type: string
- categoryFormatter:
- type: string
- seriesLabels:
- description: ArrayNode of series labels
- type: array
- items:
- type: string
- seriesFunction:
- type: string
- seriesFormatter:
- type: string
- scaleLabels:
- description: ArrayNode of filter labels
- type: array
- items:
- type: string
- scaleFunction:
- type: string
- scaleFormatter:
- type: string
- scaleDescription:
- type: string
- components:
- description: List of ReportComponents
- type: array
- items:
- description: Report Component
- required:
- - name
- - order
- - labels
- type: object
- properties:
- id:
- format: int32
- type: integer
- name:
- type: string
- order:
- format: int32
- type: integer
- labels:
- description: Array of labels
- type: array
- items:
- type: string
- example:
- - Framework
- function:
- type: string
- unit:
- type: string
- reportId:
- format: int32
- type: integer
- created:
- format: date-time
- description: Created timestamp
- type: string
- example: 2019-09-26T07:58:30.996+0200
- comments:
- description: List of ReportComments
- type: array
- items:
- required:
- - level
- - comment
- type: object
- properties:
- id:
- format: int32
- type: integer
- level:
- format: int32
- type: integer
- category:
- type: string
- componentId:
- format: int32
- type: integer
- comment:
- type: string
- data:
- description: List of TableReportData
- type: array
- items:
- description: Table Report Data
- required:
- - datasetId
- - runId
- - ordinal
- - category
- - series
- - scale
- - values
- type: object
- properties:
- datasetId:
- format: int32
- type: integer
- runId:
- format: int32
- type: integer
- ordinal:
- format: int32
- type: integer
- category:
- type: string
- series:
- type: string
- scale:
- type: string
- values:
- description: Array of values
- type: array
- items:
- type: number
- logs:
- description: List of ReportLogs
- type: array
- items:
- description: Report Log
- required:
- - reportId
- type: object
- allOf:
- - $ref: '#/components/schemas/PersistentLog'
- properties:
- reportId:
- format: int32
- type: integer
- TableReportConfig:
- description: Table Report Config
- required:
- - id
- - title
- - seriesLabels
- - components
- type: object
- properties:
- id:
- format: int32
- type: integer
- title:
- type: string
- test:
- $ref: '#/components/schemas/Test'
- filterLabels:
- description: ArrayNode of filter labels
- type: array
- items:
- type: string
- filterFunction:
- type: string
- categoryLabels:
- description: ArrayNode of category labels
- type: array
- items:
- type: string
- categoryFunction:
- type: string
- categoryFormatter:
- type: string
- seriesLabels:
- description: ArrayNode of series labels
- type: array
- items:
- type: string
- seriesFunction:
- type: string
- seriesFormatter:
- type: string
- scaleLabels:
- description: ArrayNode of filter labels
- type: array
- items:
- type: string
- scaleFunction:
- type: string
- scaleFormatter:
- type: string
- scaleDescription:
- type: string
- components:
- description: List of ReportComponents
- type: array
- items:
- description: Report Component
- required:
- - name
- - order
- - labels
- type: object
- properties:
- id:
- format: int32
- type: integer
- name:
- type: string
- order:
- format: int32
- type: integer
- labels:
- description: Array of labels
- type: array
- items:
- type: string
- example:
- - Framework
- function:
- type: string
- unit:
- type: string
- reportId:
- format: int32
- type: integer
- TableReportData:
- description: Table Report Data
- required:
- - datasetId
- - runId
- - ordinal
- - category
- - series
- - scale
- - values
- type: object
- properties:
- datasetId:
- format: int32
- type: integer
- runId:
- format: int32
- type: integer
- ordinal:
- format: int32
- type: integer
- category:
- type: string
- series:
- type: string
- scale:
- type: string
- values:
- description: Array of values
- type: array
- items:
- type: number
- Test:
- description: Represents a Test. Tests are typically equivalent to a particular
- benchmark
- required:
- - id
- - name
- - datastoreId
- - notificationsEnabled
- type: object
- allOf:
- - $ref: '#/components/schemas/ProtectedType'
- properties:
- id:
- format: int32
- description: Unique Test id
- type: integer
- example: 101
- name:
- description: Test name
- type: string
- example: my-comprehensive-benchmark
- folder:
- description: Name of folder that the test is stored in. Folders allow tests
- to be organised in the UI
- type: string
- example: My Team Folder
- description:
- description: Description of the test
- type: string
- example: Comprehensive benchmark to tests the limits of any system it is
- run against
- datastoreId:
- format: int32
- description: backend ID for backing datastore
- type: integer
- tokens:
- description: Array of API tokens associated with test
- type: array
- items:
- $ref: '#/components/schemas/TestToken'
- timelineLabels:
- description: List of label names that are used for determining metric to
- use as the time series
- type: array
- items:
- type: string
- example:
- - timestamp
- timelineFunction:
- description: Label function to modify timeline labels to a produce a value
- used for ordering datapoints
- type: string
- example: timestamp => timestamp
- fingerprintLabels:
- description: 'Array of Label names that are used to create a fingerprint '
- type: array
- items:
- type: string
- example:
- - build_tag
- fingerprintFilter:
- description: Filter function to filter out datasets that are comparable
- for the purpose of change detection
- type: string
- example: value => value === "true"
- compareUrl:
- description: URL to external service that can be called to compare runs. This
- is typically an external reporting/visulization service
- type: string
- example: "(ids, token) => 'http://repoting.example.com/report/specj?q='\
- \ + ids.join('&q=') + \"&token=\"+token"
- transformers:
- description: Array for transformers defined for the Test
- type: array
- items:
- $ref: '#/components/schemas/Transformer'
- notificationsEnabled:
- description: Are notifications enabled for the test
- type: boolean
- example: true
- TestExport:
- description: Represents a Test with all associated data used for export/import
- operations.
- type: object
- allOf:
- - $ref: '#/components/schemas/Test'
- properties:
- variables:
- description: Array of Variables associated with test
- type: array
- items:
- $ref: '#/components/schemas/Variable'
- missingDataRules:
- description: Array of MissingDataRules associated with test
- type: array
- items:
- $ref: '#/components/schemas/MissingDataRule'
- experiments:
- description: Array of ExperimentProfiles associated with test
- type: array
- items:
- $ref: '#/components/schemas/ExperimentProfile'
- actions:
- description: Array of Actions associated with test
- type: array
- items:
- $ref: '#/components/schemas/Action'
- subscriptions:
- description: Watcher object associated with test
- type: object
- allOf:
- - $ref: '#/components/schemas/Watch'
- datastore:
- description: Datastore associated with test
- type: object
- allOf:
- - $ref: '#/components/schemas/Datastore'
- TestListing:
- required:
- - tests
- - count
- type: object
- properties:
- tests:
- description: Array of Test Summaries
- type: array
- items:
- $ref: '#/components/schemas/TestSummary'
- count:
- format: int64
- description: Number of tests when pagination is ignored
- type: integer
- TestQueryResult:
- required:
- - tests
- - count
- type: object
- properties:
- tests:
- description: Array of Tests
- type: array
- items:
- $ref: '#/components/schemas/Test'
- count:
- format: int64
- description: Count of available tests. This is a count of tests that the
- current user has access to
- type: integer
- example: 64
- TestSummary:
- required:
- - id
- - name
- - datastoreId
- type: object
- allOf:
- - $ref: '#/components/schemas/ProtectedType'
- properties:
- id:
- format: int32
- description: ID of tests
- type: integer
- example: 101
- name:
- description: Test name
- type: string
- example: my-comprehensive-benchmark
- folder:
- description: Name of folder that the test is stored in. Folders allow tests
- to be organised in the UI
- type: string
- example: My Team Folder
- description:
- description: Description of the test
- type: string
- example: Comprehensive benchmark to tests the limits of any system it is
- run against
- datasets:
- description: Total number of Datasets for the Test
- type: number
- example: 202
- runs:
- description: Total number of Runs for the Test
- type: number
- example: 101
- watching:
- description: Subscriptions for each test for authenticated user
- uniqueItems: true
- type: array
- items:
- type: string
- example: []
- datastoreId:
- format: int32
- description: Datastore id
- type: integer
- example: 1
- TestToken:
- required:
- - id
- - value
- - permissions
- - description
- type: object
- properties:
- id:
- format: int32
- description: Unique Token id
- type: integer
- example: 101
- testId:
- format: int32
- description: Test ID to apply Token
- type: integer
- example: 201
- value:
- description: Test value
- type: string
- example: 094678029a2aaf9a2847502273099bb3a1b2338c2b9c618ed09aef0181666e38
- permissions:
- format: int32
- type: integer
- description:
- description: Token description
- type: string
- example: my reporting service token
- TransformationLog:
- description: Transformation Log
- required:
- - id
- - level
- - timestamp
- - message
- type: object
- properties:
- id:
- format: int64
- type: integer
- level:
- format: int32
- type: integer
- timestamp:
- format: date-time
- type: string
- example: 2022-03-10T16:15:50Z
- message:
- type: string
- testId:
- format: int32
- type: integer
- runId:
- format: int32
- type: integer
- Transformer:
- description: A transformer extracts labals and applies a Function to convert
- a Run into one or more Datasets
- required:
- - id
- - name
- - extractors
- - schemaId
- - schemaUri
- - schemaName
- type: object
- allOf:
- - $ref: '#/components/schemas/ProtectedType'
- properties:
- id:
- format: int32
- description: Unique Transformer id
- type: integer
- example: 101
- name:
- description: Transformer name
- type: string
- example: normalize-techempower-result
- description:
- description: Transformer description
- type: string
- example: Normalizers a techempower output file to separate each framework
- into a dataset and normalize the JSON structure
- targetSchemaUri:
- description: "The schema associated with the calculated Datasets. Where\
- \ a transformer creates a new JSON object with a new structure, this Schema\
- \ is used to extafct values from the new Dataset JSON document"
- type: string
- example: uri:normalized-techempower:0.1
- extractors:
- description: A collection of extractors to extract JSON values to create
- new Dataset JSON document
- type: array
- items:
- $ref: '#/components/schemas/Extractor'
- function:
- type: string
- schemaId:
- format: int32
- description: Schema ID that the transform is registered against
- type: integer
- example: 101
- schemaUri:
- description: Schema Uri that the transform is registered against
- type: string
- example: urn:techempower:0.1
- schemaName:
- description: Schema name that the transform is registered against
- type: string
- example: techempower
- TransformerInfo:
- required:
- - schemaId
- - schemaUri
- - schemaName
- - transformerId
- - transformerName
- type: object
- properties:
- schemaId:
- format: int32
- description: Schema ID
- type: integer
- example: 101
- schemaUri:
- description: Schema uri
- type: string
- example: uri:my-schema:0.1
- schemaName:
- description: Schema name
- type: string
- example: my-benchmark-schema
- transformerId:
- format: int32
- description: Transformer ID
- type: integer
- example: 201
- transformerName:
- description: Transformer name
- type: string
- example: my-dataset-transformer
- ValidationError:
- required:
- - schemaId
- - error
- type: object
- properties:
- schemaId:
- format: int32
- description: Schema ID that Validation Error relates to
- type: integer
- example: 101
- error:
- description: Validation Error Details
- type: object
- allOf:
- - $ref: '#/components/schemas/ErrorDetails'
- Variable:
- required:
- - id
- - testId
- - name
- - order
- - labels
- - changeDetection
- type: object
- properties:
- id:
- format: int32
- type: integer
- testId:
- format: int32
- type: integer
- name:
- type: string
- group:
- type: string
- order:
- format: int32
- type: integer
- labels:
- type: array
- items:
- type: string
- calculation:
- type: string
- changeDetection:
- type: array
- items:
- $ref: '#/components/schemas/ChangeDetection'
- VersionInfo:
- required:
- - version
- - startTimestamp
- type: object
- properties:
- version:
- description: Version of Horreum
- type: string
- example: 0.9.4
- startTimestamp:
- format: int64
- description: Timestamp of server startup
- type: integer
- example: 2023-10-18 18:00:57
- privacyStatement:
- description: Privacy statement
- type: string
- example: link/to/external/privacy/statement
- Watch:
- required:
- - users
- - optout
- - teams
- - testId
- type: object
- properties:
- id:
- format: int32
- type: integer
- users:
- type: array
- items:
- type: string
- optout:
- type: array
- items:
- type: string
- teams:
- type: array
- items:
- type: string
- testId:
- format: int32
- type: integer
diff --git a/poetry.lock b/poetry.lock
index 0bb9249..6515303 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -22,6 +22,20 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
trio = ["trio (>=0.23)"]
+[[package]]
+name = "argcomplete"
+version = "3.2.3"
+description = "Bash tab completion for argparse"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "argcomplete-3.2.3-py3-none-any.whl", hash = "sha256:c12355e0494c76a2a7b73e3a59b09024ca0ba1e279fb9ed6c1b82d5b74b6a70c"},
+ {file = "argcomplete-3.2.3.tar.gz", hash = "sha256:bf7900329262e481be5a15f56f19736b376df6f82ed27576fa893652c5de6c23"},
+]
+
+[package.extras]
+test = ["coverage", "mypy", "pexpect", "ruff", "wheel"]
+
[[package]]
name = "certifi"
version = "2024.2.2"
@@ -207,6 +221,23 @@ files = [
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
+[[package]]
+name = "colorlog"
+version = "6.8.2"
+description = "Add colours to the output of Python's logging module."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "colorlog-6.8.2-py3-none-any.whl", hash = "sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33"},
+ {file = "colorlog-6.8.2.tar.gz", hash = "sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+
+[package.extras]
+development = ["black", "flake8", "mypy", "pytest", "types-colorama"]
+
[[package]]
name = "cryptography"
version = "42.0.5"
@@ -292,6 +323,17 @@ files = [
[package.dependencies]
packaging = "*"
+[[package]]
+name = "distlib"
+version = "0.3.8"
+description = "Distribution utilities"
+optional = false
+python-versions = "*"
+files = [
+ {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
+ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
+]
+
[[package]]
name = "exceptiongroup"
version = "1.2.0"
@@ -306,6 +348,22 @@ files = [
[package.extras]
test = ["pytest (>=6)"]
+[[package]]
+name = "filelock"
+version = "3.13.1"
+description = "A platform independent file lock."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"},
+ {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
+typing = ["typing-extensions (>=4.8)"]
+
[[package]]
name = "h11"
version = "0.14.0"
@@ -548,6 +606,43 @@ files = [
microsoft-kiota_abstractions = ">=1.0.0,<2.0.0"
python-dateutil = ">=2.8.2"
+[[package]]
+name = "nox"
+version = "2024.3.2"
+description = "Flexible test automation."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "nox-2024.3.2-py3-none-any.whl", hash = "sha256:e53514173ac0b98dd47585096a55572fe504fecede58ced708979184d05440be"},
+ {file = "nox-2024.3.2.tar.gz", hash = "sha256:f521ae08a15adbf5e11f16cb34e8d0e6ea521e0b92868f684e91677deb974553"},
+]
+
+[package.dependencies]
+argcomplete = ">=1.9.4,<4.0"
+colorlog = ">=2.6.1,<7.0.0"
+packaging = ">=20.9"
+virtualenv = ">=20.14.1"
+
+[package.extras]
+tox-to-nox = ["jinja2", "tox"]
+uv = ["uv"]
+
+[[package]]
+name = "nox-poetry"
+version = "1.0.3"
+description = "nox-poetry"
+optional = false
+python-versions = ">=3.7,<4.0"
+files = [
+ {file = "nox_poetry-1.0.3-py3-none-any.whl", hash = "sha256:a2fffeb70ae81840479e68287afe1c772bf376f70f1e92f99832a20b3c64d064"},
+ {file = "nox_poetry-1.0.3.tar.gz", hash = "sha256:dc7ecbbd812a333a0c0b558f57e5b37f7c12926cddbcecaf2264957fd373824e"},
+]
+
+[package.dependencies]
+nox = ">=2020.8.22"
+packaging = ">=20.9"
+tomlkit = ">=0.7"
+
[[package]]
name = "opentelemetry-api"
version = "1.23.0"
@@ -700,6 +795,21 @@ tzdata = ">=2020.1"
[package.extras]
test = ["time-machine (>=2.6.0)"]
+[[package]]
+name = "platformdirs"
+version = "4.2.0"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"},
+ {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
+
[[package]]
name = "pluggy"
version = "1.4.0"
@@ -879,6 +989,17 @@ files = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
+[[package]]
+name = "tomlkit"
+version = "0.12.4"
+description = "Style preserving TOML library"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b"},
+ {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"},
+]
+
[[package]]
name = "typing-extensions"
version = "4.10.0"
@@ -918,6 +1039,26 @@ h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
+[[package]]
+name = "virtualenv"
+version = "20.25.1"
+description = "Virtual Python Environment builder"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"},
+ {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"},
+]
+
+[package.dependencies]
+distlib = ">=0.3.7,<1"
+filelock = ">=3.12.2,<4"
+platformdirs = ">=3.9.1,<5"
+
+[package.extras]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
+test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
+
[[package]]
name = "wrapt"
version = "1.16.0"
@@ -1014,5 +1155,5 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata]
lock-version = "2.0"
-python-versions = "^3.10"
-content-hash = "0f259faa8559a5a87db0e93a4368724eef579cd8a321eee8ce8c90afd962d2f3"
+python-versions = "^3.9"
+content-hash = "61822287999dc23a35ed9e47ff476c46cff4d4ce68c4569c738d753e23d7c2df"
diff --git a/pyproject.toml b/pyproject.toml
index 69ecdcb..bc875b7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,15 +2,25 @@
name = "horreum"
version = "0.13-dev"
description = "Horreum python library"
+keywords = ["horreum", "performance", "change-detection"]
authors = ["Andrea Lamparelli "]
+maintainers = [
+ "Andrea Lamparelli ",
+ "John O'Hara ",
+ "Stale Pedersen "
+]
license = "Apache 2.0"
readme = "README.md"
+homepage = "https://github.com/Hyperfoil/horreum-client-python"
include = [
- "src/horreum/raw_client/**/*", # all files in "src/horreum/raw_client" and any subfolders
+ "src/horreum/raw_client/**/*", # this folder includes auto-generated client
]
+[tool.poetry.urls]
+"Issues" = "https://github.com/Hyperfoil/horreum-client-python/issues"
+
[tool.poetry.dependencies]
-python = "^3.10"
+python = "^3.9"
microsoft-kiota-abstractions = "^1.3.1"
microsoft-kiota-http = "^1.3.1"
microsoft-kiota-serialization-json = "^1.1.0"
@@ -23,6 +33,8 @@ microsoft-kiota-serialization-multipart = "^0.1.0"
[tool.poetry.group.dev.dependencies]
pytest = "^8.1.1"
pytest-asyncio = "^0.23.6"
+nox = "^2024.3.2"
+nox-poetry = "^1.0.3"
[build-system]
requires = ["poetry-core"]
diff --git a/src/horreum/horreum_client.py b/src/horreum/horreum_client.py
index cd673d6..41d1a3d 100644
--- a/src/horreum/horreum_client.py
+++ b/src/horreum/horreum_client.py
@@ -1,3 +1,5 @@
+from importlib.metadata import version
+
from kiota_abstractions.authentication import AuthenticationProvider
from kiota_abstractions.authentication.access_token_provider import AccessTokenProvider
from kiota_abstractions.authentication.anonymous_authentication_provider import AnonymousAuthenticationProvider
@@ -6,9 +8,7 @@
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
from .keycloak_access_provider import KeycloakAccessProvider
-from .raw_client import HorreumRawClient
-
-from .service import info_service as info
+from .raw_client.horreum_raw_client import HorreumRawClient
async def setup_auth_provider(base_url: str, username: str, password: str) -> AccessTokenProvider:
@@ -61,8 +61,9 @@ async def setup(self):
# High-level API #
##################
- def version(self) -> str:
- return info.get_client_version()
+ @staticmethod
+ def version() -> str:
+ return version("horreum")
async def new_horreum_client(base_url: str, username: str = None, password: str = None) -> HorreumClient:
diff --git a/src/horreum/raw_client/.gitignore b/src/horreum/raw_client/.gitignore
deleted file mode 100644
index 266de2d..0000000
--- a/src/horreum/raw_client/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# Ignore everything, this dir will contain generated code
-*
-
-# Keep this file versioned
-!__init__.py
\ No newline at end of file
diff --git a/src/horreum/raw_client/__init__.py b/src/horreum/raw_client/__init__.py
deleted file mode 100644
index 4f4fe7c..0000000
--- a/src/horreum/raw_client/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from .horreum_raw_client import HorreumRawClient
-
-__all__ = [
- HorreumRawClient
-]
diff --git a/src/horreum/service/__init__.py b/src/horreum/service/__init__.py
deleted file mode 100644
index 4d79f23..0000000
--- a/src/horreum/service/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# from .info_service import get_client_version
-
-__all__ = [
- "info_service"
-]
diff --git a/src/horreum/service/info_service.py b/src/horreum/service/info_service.py
deleted file mode 100644
index ea97e66..0000000
--- a/src/horreum/service/info_service.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from importlib.metadata import version
-
-
-def get_client_version():
- return version("horreum")
diff --git a/test/workflow_dispatch_event_example.json b/test/gha_workflows/workflow_dispatch_event_example.json
similarity index 100%
rename from test/workflow_dispatch_event_example.json
rename to test/gha_workflows/workflow_dispatch_event_example.json
diff --git a/test/horreum_client_it.py b/test/horreum_client_it.py
new file mode 100644
index 0000000..2423b6b
--- /dev/null
+++ b/test/horreum_client_it.py
@@ -0,0 +1,93 @@
+import httpx
+import pytest
+from kiota_abstractions.authentication import BaseBearerTokenAuthenticationProvider
+from kiota_abstractions.base_request_configuration import RequestConfiguration
+from kiota_abstractions.headers_collection import HeadersCollection
+from kiota_abstractions.method import Method
+from kiota_abstractions.request_information import RequestInformation
+
+from horreum.horreum_client import new_horreum_client, HorreumClient
+from horreum.raw_client.api.test.test_request_builder import TestRequestBuilder
+from horreum.raw_client.models.protected_type_access import ProtectedType_access
+from horreum.raw_client.models.test import Test
+
+username = "user"
+password = "secret"
+
+
+@pytest.fixture()
+async def anonymous_client_without_check() -> HorreumClient:
+ print("Setting up anonymous client")
+ return await new_horreum_client(base_url="http://localhost:8080")
+
+
+@pytest.fixture()
+async def anonymous_client() -> HorreumClient:
+ print("Setting up anonymous client")
+ client = await new_horreum_client(base_url="http://localhost:8080")
+ try:
+ await client.raw_client.api.config.version.get()
+ except httpx.ConnectError:
+ pytest.fail("Unable to fetch Horreum version, is Horreum running in the background?")
+ return client
+
+
+@pytest.fixture()
+async def authenticated_client() -> HorreumClient:
+ print("Setting up authenticated client")
+ client = await new_horreum_client(base_url="http://localhost:8080", username=username, password=password)
+ try:
+ await client.raw_client.api.config.version.get()
+ except httpx.ConnectError:
+ pytest.fail("Unable to fetch Horreum version, is Horreum running in the background?")
+ return client
+
+
+@pytest.mark.asyncio
+async def test_check_server_version(anonymous_client: HorreumClient):
+ version = await anonymous_client.raw_client.api.config.version.get()
+ assert version.version != ""
+ assert version.start_timestamp != ""
+
+
+@pytest.mark.asyncio
+async def test_check_missing_token(anonymous_client: HorreumClient):
+ req = RequestInformation(Method("GET"), "/api/")
+ await anonymous_client.auth_provider.authenticate_request(req)
+ assert len(req.headers.get(BaseBearerTokenAuthenticationProvider.AUTHORIZATION_HEADER)) == 0
+
+
+@pytest.mark.asyncio
+async def test_check_auth_token(authenticated_client: HorreumClient):
+ req = RequestInformation(Method("GET"), "/api/")
+ await authenticated_client.auth_provider.authenticate_request(req)
+ assert len(req.headers.get(BaseBearerTokenAuthenticationProvider.AUTHORIZATION_HEADER)) == 1
+ assert req.headers.get(BaseBearerTokenAuthenticationProvider.AUTHORIZATION_HEADER).pop().startswith("Bearer")
+
+
+@pytest.mark.asyncio
+async def test_missing_username_with_password():
+ with pytest.raises(RuntimeError) as ex:
+ await new_horreum_client(base_url="http://localhost:8080", password=password)
+ assert str(ex.value) == "providing password without username, have you missed something?"
+
+
+@pytest.mark.asyncio
+async def test_check_no_tests(authenticated_client: HorreumClient):
+ query_params = TestRequestBuilder.TestRequestBuilderGetQueryParameters(limit=1, page=0)
+ config = RequestConfiguration(query_parameters=query_params, headers=HeadersCollection())
+ assert (await authenticated_client.raw_client.api.test.get(config)).count == 0
+
+
+@pytest.mark.asyncio
+async def test_check_create_test(authenticated_client: HorreumClient):
+ # Create new test
+ t = Test(name="TestName", description="Simple test", owner="dev-team", access=ProtectedType_access.PUBLIC)
+ created = await authenticated_client.raw_client.api.test.post(t)
+ assert created is not None
+ assert (await authenticated_client.raw_client.api.test.get()).count == 1
+
+ # TODO: we could automate setup/teardown process
+ # Delete test
+ await authenticated_client.raw_client.api.test.by_id(created.id).delete()
+ assert (await authenticated_client.raw_client.api.test.get()).count == 0
diff --git a/test/horreum_client_test.py b/test/horreum_client_test.py
index 450a0f7..76199af 100644
--- a/test/horreum_client_test.py
+++ b/test/horreum_client_test.py
@@ -1,101 +1,17 @@
-import httpx
import pytest
-from kiota_abstractions.authentication import BaseBearerTokenAuthenticationProvider
-from kiota_abstractions.base_request_configuration import RequestConfiguration
-from kiota_abstractions.headers_collection import HeadersCollection
-from kiota_abstractions.method import Method
-from kiota_abstractions.request_information import RequestInformation
from horreum.horreum_client import new_horreum_client, HorreumClient
-from horreum.raw_client.api.test.test_request_builder import TestRequestBuilder
-from horreum.raw_client.models.protected_type_access import ProtectedType_access
-from horreum.raw_client.models.test import Test
-
-username = "user"
-password = "secret"
-
-
-@pytest.fixture()
-async def anonymous_client_without_check() -> HorreumClient:
- print("Setting up anonymous client")
- return await new_horreum_client(base_url="http://localhost:8080")
@pytest.fixture()
async def anonymous_client() -> HorreumClient:
print("Setting up anonymous client")
client = await new_horreum_client(base_url="http://localhost:8080")
- try:
- await client.raw_client.api.config.version.get()
- except httpx.ConnectError:
- pytest.fail("Unable to fetch Horreum version, is Horreum running in the background?")
return client
-@pytest.fixture()
-async def authenticated_client() -> HorreumClient:
- print("Setting up authenticated client")
- client = await new_horreum_client(base_url="http://localhost:8080", username=username, password=password)
- try:
- await client.raw_client.api.config.version.get()
- except httpx.ConnectError:
- pytest.fail("Unable to fetch Horreum version, is Horreum running in the background?")
- return client
-
-
-def test_check_client_version(anonymous_client_without_check: HorreumClient):
- version = anonymous_client_without_check.version()
+@pytest.mark.asyncio
+async def test_check_client_version(anonymous_client: HorreumClient):
+ version = HorreumClient.version()
# TODO: we could load the toml and check the versions match
assert version != ""
-
-
-@pytest.mark.asyncio
-async def test_check_server_version(anonymous_client: HorreumClient):
- version = await anonymous_client.raw_client.api.config.version.get()
- assert version.version != ""
- assert version.start_timestamp != ""
-
-
-@pytest.mark.asyncio
-async def test_check_missing_token(anonymous_client: HorreumClient):
- req = RequestInformation(Method("GET"), "/api/")
- await anonymous_client.auth_provider.authenticate_request(req)
- assert len(req.headers.get(BaseBearerTokenAuthenticationProvider.AUTHORIZATION_HEADER)) == 0
-
-
-@pytest.mark.asyncio
-async def test_check_auth_token(authenticated_client: HorreumClient):
- req = RequestInformation(Method("GET"), "/api/")
- await authenticated_client.auth_provider.authenticate_request(req)
- assert len(req.headers.get(BaseBearerTokenAuthenticationProvider.AUTHORIZATION_HEADER)) == 1
- assert req.headers.get(BaseBearerTokenAuthenticationProvider.AUTHORIZATION_HEADER).pop().startswith("Bearer")
-
-
-@pytest.mark.asyncio
-async def test_missing_username_with_password():
- try:
- await new_horreum_client(base_url="http://localhost:8080", password=password)
- pytest.fail("expect RuntimeError here")
- except RuntimeError as e:
- assert str(e) == "providing password without username, have you missed something?"
-
-
-@pytest.mark.asyncio
-async def test_check_no_tests(authenticated_client: HorreumClient):
- query_params = TestRequestBuilder.TestRequestBuilderGetQueryParameters(limit=1, page=0)
- config = RequestConfiguration(query_parameters=query_params, headers=HeadersCollection())
- assert (await authenticated_client.raw_client.api.test.get(config)).count == 0
-
-
-@pytest.mark.asyncio
-async def test_check_create_test(authenticated_client: HorreumClient):
- # Create new test
- t = Test(name="TestName", description="Simple test", owner="dev-team", access=ProtectedType_access.PUBLIC)
- created = await authenticated_client.raw_client.api.test.post(t)
- assert created is not None
- assert (await authenticated_client.raw_client.api.test.get()).count == 1
-
- # TODO: we could automate setup/teardown process
- # Delete test
- await authenticated_client.raw_client.api.test.by_id(created.id).delete()
- assert (await authenticated_client.raw_client.api.test.get()).count == 0