diff --git a/.dockerignore b/.dockerignore index e79c44c7e..21f4569b9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,4 +2,6 @@ **/node_modules **/.pytest_cache *.iml -.idea/ \ No newline at end of file +.idea/ +web-frontend/reports/ +backend/reports/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 093a5b4fd..6e1328e06 100644 --- a/.gitignore +++ b/.gitignore @@ -96,6 +96,8 @@ venv/ web-frontend/plugins/ backend/plugins/ +web-frontend/reports/ +backend/reports/ .idea/ *.iml @@ -115,3 +117,6 @@ out/ vetur.config.js formula/out/ + +.coverage +junit.xml \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a50d8a3f9..39ce89b36 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,70 +1,599 @@ -before_script: - - apt-get update && apt-get -y install make curl gnupg2 +# == Summary of Baserow's CI workflow: +# +# This file contains the gitlab CI job definitions that build and test Baserow +# automatically. +# +# === Overview of how Baserow uses git branches +# +# * `develop` is the branch we merge newly developed features onto from feature +# branches. +# * a feature branch is a branch made starting off `develop` containing a specific +# new feature, when finished it will be merged back onto `develop`. +# * `master` is the branch which contains official releases of Baserow, to do so we +# periodically merge the latest changes from `develop` onto `master` and then tag +# that new master commit with a git tag containing the version (1.8.2 etc). +# +# === How new version of Baserow is released to Dockerhub +# +# A. Create an MR from develop to master and merge it. +# B. Wait for the merge commit pipeline succeed on master which will build and test the +# images. +# C. Tag the merge commit in the Gitlab GUI with the git tag being the Baserow version +# (1.8.2, 1.0, etc). +# D. Gitlab will make a new pipeline for the tag which will push the images built in +# step B to Dockerhub. If step B failed or has not completed yet then this pipeline +# will fail and not push anything. +# +# === What Gitlab CI steps are configured to run and when +# +# See below for the high level summary of the steps Gitlab will run to build, test and +# release Baserow images in various scenarios depending on the branches involved. +# +# ==== On the master branch - When MR Merged/commit pushed/branch made +# +# 1. The backend and web-frontend dev images will be built and pushed to the +# gitlab ci image repo. +# 1. A `{image_dev}:ci-latest-$CI_COMMIT_SHA` image is pushed for the next stages. +# 2. A `{image_dev}:ci-latest-$BRANCH_NAME` image is pushed to cache future runs. +# 2. The pushed `ci-latest-$CI_COMMIT_SHA` images will be tested and linted. If a +# previously successful test/lint run is found for the same/prev commit AND no +# files have changed which could possibly change the result this is skipped. +# 3. Cached from the `ci-latest-$CI_COMMIT_SHA` image the non-dev images will be built +# and then both the dev and non-dev images will be with tagged marking them as +# tested and pushed to the gitlab ci repo. +# 4. Trigger a pipeline in any downstream repos that depend on this one. +# +# ==== On the develop branch - When MR Merged/new commit pushed +# +# The build and testing steps 1, 2 and 3 from above are run first and then: +# 4. Push the tested images from step 3 to the Dockerhub repo under the +# `develop-latest` tag. +# 5. Trigger a pipeline in any downstream repos that depend on this one. +# +# ==== On feature branches - When MR Merged/new commit pushed +# +# The build and testing steps 1, 2 and 3 from above are run. +# +# ===== On the latest commit on master - When a Git tag is created +# +# This is done when we have merged the latest changes from develop on master, and we +# want to release them as a new version of Baserow. Gitlab will automatically detect +# the new git tag and only do the following: +# +# 1. Push the images built from step 3 above (or fail if they don't exist) to the +# Dockerhub repo with the tags: +# 1. `latest` +# 2. `${git tag}` +# +# ==== Older commit on master - When a Git tag created +# +# 1. Push the images built from step 3 above (or fail if they don't exist) to the +# Dockerhub repo with the tags: +# 1. `${git tag}` +# +# ==== Any non-master commit - When a Git tag created +# +# 1. Fail as only master commits should be tagged/released. +# +# == Cleanup +# +# Images with tags starting with `ci-latest` or `ci-tested` (made in steps 1. and 3.) +# will be deleted after they are 7 days old by a job that runs daily at 11AM CET. + +include: '/.gitlab/ci_includes/jobs.yml' stages: - - lint - - test - build + - test + - build-final + - publish -web-frontend-eslint: - stage: lint - image: node:12 - script: - - cd web-frontend - - make install-dependencies - - make eslint +variables: + ENABLE_JOB_SKIPPING: + value: "true" + description: "If set to false then tests and lints will be forced to run and not use previously cached results." + ENABLE_COVERAGE: + value: "true" + description: "If set to false then tests will not generate coverage or testing reports used by gitlab to show nicer MRs." + # An image repo which is used for storing and passing images between ci pipeline jobs + # and also speeding up ci builds by caching from the latest ci image when building. + CI_IMAGE_REPO: $CI_REGISTRY_IMAGE/ci + # Any images with tags prefixed with the two variables below will be cleaned up automatically + # by our gitlab cleanup job: + # (https://gitlab.com/bramw/baserow/-/settings/packages_and_registries). + # + # ## Note: + # These cleanup tag prefixes are needed as gitlab only supports cleanup by defining + # a regex that matches tags, so we can't do cleanup differently based on image name + # or repo... + # + # IMPORTANT: UPDATE GITLAB CONTAINER REPO CLEANUP JOB REGEX IF YOU CHANGE THIS + CLEANUP_JOB_CI_TAG_PREFIX: ci-latest- + # IMPORTANT: UPDATE GITLAB CONTAINER REPO CLEANUP JOB REGEX IF YOU CHANGE THIS + TESTED_IMAGE_PREFIX: ci-tested- + # An image repo where dev and normal images will be released to for public usage after + # they have been successfully built and tested. + RELEASE_IMAGE_REPO: $CI_REGISTRY_IMAGE/testing + BACKEND_IMAGE_NAME: backend + BACKEND_DEV_IMAGE_NAME: backend_dev + WEBFRONTEND_IMAGE_NAME: web-frontend + WEBFRONTEND_DEV_IMAGE_NAME: web-frontend_dev + BACKEND_CI_DEV_IMAGE: $CI_IMAGE_REPO/$BACKEND_DEV_IMAGE_NAME:$CLEANUP_JOB_CI_TAG_PREFIX$CI_COMMIT_SHORT_SHA + WEBFRONTEND_CI_DEV_IMAGE: $CI_IMAGE_REPO/$WEBFRONTEND_DEV_IMAGE_NAME:$CLEANUP_JOB_CI_TAG_PREFIX$CI_COMMIT_SHORT_SHA + # Once images are tested they will publish under these names to ensure that any + # tag only runs of the pipeline can never publish untested images. + TESTED_BACKEND_CI_IMAGE: $CI_IMAGE_REPO/$BACKEND_IMAGE_NAME:$TESTED_IMAGE_PREFIX$CI_COMMIT_SHORT_SHA + TESTED_WEBFRONTEND_CI_IMAGE: $CI_IMAGE_REPO/$WEBFRONTEND_IMAGE_NAME:$TESTED_IMAGE_PREFIX$CI_COMMIT_SHORT_SHA + TESTED_BACKEND_CI_DEV_IMAGE: $CI_IMAGE_REPO/$BACKEND_DEV_IMAGE_NAME:$TESTED_IMAGE_PREFIX$CI_COMMIT_SHORT_SHA + TESTED_WEBFRONTEND_CI_DEV_IMAGE: $CI_IMAGE_REPO/$WEBFRONTEND_DEV_IMAGE_NAME:$TESTED_IMAGE_PREFIX$CI_COMMIT_SHORT_SHA + # Used to tag the latest images on $DEVELOP_BRANCH_NAME + DEVELOP_LATEST_TAG: develop-latest + # Names of important branches used to decide when to run certain jobs. + MASTER_BRANCH_NAME: master + DEVELOP_BRANCH_NAME: develop + # The locations of the various dockerfiles to build. + BACKEND_DOCKERFILE_PATH: $CI_PROJECT_DIR/backend/Dockerfile + WEBFRONTEND_DOCKERFILE_PATH: $CI_PROJECT_DIR/web-frontend/Dockerfile + # The image path for the helper CI util image that will be built and pushed to. + CI_UTIL_IMAGE: $CI_IMAGE_REPO/ci_util_image:latest -web-frontend-stylelint: - stage: lint - image: node:12 - script: - - cd web-frontend - - make install-dependencies - - make stylelint - -web-frontend-test: - stage: test - image: node:12 - script: - - cd web-frontend - - make install-dependencies - - make test - -backend-flake8: - stage: lint - image: python:3.7 - script: - - cd backend - - make install-dependencies - - make install-dev-dependencies - - make lint - -backend-pytest: - stage: test - image: python:3.7 +build-ci-util-image: + image: docker:20.10.12 + stage: build services: + - docker:20.10.12-dind + variables: + DOCKER_BUILDKIT: 1 + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_CERTDIR: "/certs" + before_script: + - | + echo "$CI_REGISTRY_PASSWORD" | \ + docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin + script: + - cd .gitlab/ci_util_image + - docker build -t $CI_UTIL_IMAGE . + - docker push $CI_UTIL_IMAGE + only: + changes: + - .gitlab/ci_util_image/* + +# If pipeline not triggered by tag : +# - Builds the backend dev image and stores in ci repo for next stages. +build-backend-image: + extends: .build-baserow-image + variables: + DEV_IMAGE_NAME: $BACKEND_DEV_IMAGE_NAME + DOCKERFILE_PATH: $BACKEND_DOCKERFILE_PATH + +# If pipeline not triggered by tag and backend code has changed: +# - Runs the backend lint +backend-lint: + extends: + - .docker-image-test-stage + script: + - docker run --rm $BACKEND_CI_DEV_IMAGE lint + only: + # Skip linting if no change to files + changes: + - backend/**/* + - premium/backend/**/* + +# If pipeline not triggered by tag and backend code has not changed: +# - If there is a previous successful backend lint run in the cache then skip. +# - Otherwise runs backend lint. +no-backend-changes-so-try-skip-lint: + extends: + - .skippable-job + - backend-lint + variables: + SKIP_JOB_NAME: backend-lint + # Override inherited only block, so we can run this job in the + # exact opposite situations. + only: null + except: + changes: + - backend/**/* + - premium/backend/**/* + +# If pipeline not triggered by tag and backend code has changed: +# - Runs the backend tests (the first 1/3) +# - Generates coverage db's and stores as artifact for later coverage merge and report +backend-test-group-1: + extends: + - .docker-image-test-stage + services: + - docker:20.10.12-dind - name: postgres:11.3 alias: db - name: liminspace/mjml-tcpserver:0.10 alias: mjml variables: + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_CERTDIR: "/certs" POSTGRES_USER: baserow POSTGRES_PASSWORD: baserow POSTGRES_DB: baserow + PYTEST_SPLIT_GROUP: 1 script: - - cd backend - - make install-dependencies - - make install-dev-dependencies - - export PYTHONPATH=$CI_PROJECT_DIR/backend/src:$CI_PROJECT_DIR/premium/backend/src - - make test + - MJML_IP=$(cat /etc/hosts | awk '{if ($2 == "mjml") print $1;}') + - ping -w 2 $MJML_IP + - DB_IP=$(cat /etc/hosts | awk '{if ($2 == "db") print $1;}') + - ping -w 2 $DB_IP + - mkdir -p reports + - TEST_TYPE=$([[ "$ENABLE_COVERAGE" = "true" ]] && echo "ci-test" || echo "test") + - | + docker run \ + -e PYTEST_SPLITS=3 \ + -e PYTEST_SPLIT_GROUP=$PYTEST_SPLIT_GROUP \ + --name=baserow_backend_test_container \ + --add-host="db:$DB_IP" \ + --add-host="mjml:$MJML_IP" \ + $BACKEND_CI_DEV_IMAGE $TEST_TYPE; + - docker cp baserow_backend_test_container:/baserow/backend/reports . + - docker rm baserow_backend_test_container + - | + if [[ $PYTEST_SPLIT_GROUP = 1 ]]; then + docker run -e DATABASE_USER=baserow \ + -e DATABASE_NAME=baserow \ + -e DATABASE_HOST=db \ + -e DATABASE_PASSWORD=baserow \ + --rm \ + --add-host="db:$DB_IP" \ + --add-host="mjml:$MJML_IP" \ + $BACKEND_CI_DEV_IMAGE ci-check-startup; + fi + only: + # Skip testing on if no change to backend files + changes: + - backend/**/* + - premium/backend/**/* + artifacts: + paths: + - reports/ + reports: + junit: reports/report.xml -backend-setup: - stage: build - image: python:3.7 +# If pipeline not triggered by tag and backend code has not changed: +# - If there is a previous successful backend test run then download and reuse its +# artifacts (coverage etc). +# - Otherwise runs the backend-test job like normal. +no-backend-changes-so-try-skip-tests-group-1: + extends: + - backend-test-group-1 + - .skippable-job + variables: + SKIP_JOB_NAME: backend-test-group-1 + DOWNLOAD_AND_UNPACK_ARTIFACTS_ON_SKIP: 'true' + # Override inherited only block, so we can run this job in the + # exact opposite situations. + only: null + except: + changes: + - backend/**/* + - premium/backend/**/* + +# Create 2 more separate groups to parallelize pytest by using separate groups to +# decrease overall build time. Pytest xdist doesn't help as the gitlab saas runners only +# have a single virtual core so `pytest -n 2+` slows things down. +backend-test-group-2: + extends: backend-test-group-1 + variables: + PYTEST_SPLIT_GROUP: 2 + +no-backend-changes-so-try-skip-tests-group-2: + extends: no-backend-changes-so-try-skip-tests-group-1 + variables: + SKIP_JOB_NAME: backend-test-group-2 + PYTEST_SPLIT_GROUP: 2 + +backend-test-group-3: + extends: backend-test-group-1 + variables: + PYTEST_SPLIT_GROUP: 3 + +no-backend-changes-so-try-skip-tests-group-3: + extends: no-backend-changes-so-try-skip-tests-group-1 + variables: + SKIP_JOB_NAME: backend-test-group-3 + PYTEST_SPLIT_GROUP: 3 + +# Collects together all the separate backend coverage databases from previous jobs and +# combines them to generate a single report for gitlab to use. Gitlab itself does not +# correctly merge these if you just add them all separately into artifacts->reports-> +# cobertura. +backend-coverage: + image: $CI_UTIL_IMAGE + stage: build-final + interruptible: true + only: + variables: + - $ENABLE_COVERAGE == "true" + # Prevent rebuilds when tagging as all we want to do is tag and push + except: + variables: + - $CI_COMMIT_TAG + # Depend on the `reports` artifacts from the previous jobs + dependencies: + - backend-test-group-1 + - backend-test-group-2 + - backend-test-group-3 + # If the actual tests were skipped then the artifacts will be on these jobs instead + - no-backend-changes-so-try-skip-tests-group-1 + - no-backend-changes-so-try-skip-tests-group-2 + - no-backend-changes-so-try-skip-tests-group-3 script: - - pip install -e ./backend - - python -c 'import baserow' - - pip install -e ./premium/backend - - python -c 'import baserow_premium' - - export DJANGO_SETTINGS_MODULE='baserow.config.settings.base' - - timeout --preserve-status 10s gunicorn --workers=1 -b 0.0.0.0:8000 -k uvicorn.workers.UvicornWorker baserow.config.asgi:application + - . /baserow/venv/bin/activate + # The reports artifacts will be extracted before the script runs into reports by + # gitlab + - cp reports/.coverage.* . + - export COVERAGE_RCFILE=backend/.coveragerc + - coverage combine + - coverage report + - coverage xml -o coverage.xml + artifacts: + reports: + cobertura: coverage.xml + coverage: '/^TOTAL.+?(\d+\%)$/' + +# If pipeline not triggered by tag: +# - Build and store non-dev images in CI repo under the `ci-tested` tag so we know +# those images have passed the tests. +build-final-backend-image: + extends: .build-final-baserow-image + variables: + IMAGE_NAME: $BACKEND_IMAGE_NAME + DEV_IMAGE_NAME: $BACKEND_DEV_IMAGE_NAME + DOCKERFILE_PATH: $BACKEND_DOCKERFILE_PATH + +# ==================================== WEB-FRONTEND ==================================== + +# If pipeline not triggered by tag: +# - Builds the web-frontend dev image and stores in ci repo for next stages. +build-web-frontend-image: + extends: .build-baserow-image + variables: + DEV_IMAGE_NAME: $WEBFRONTEND_DEV_IMAGE_NAME + DOCKERFILE_PATH: $WEBFRONTEND_DOCKERFILE_PATH + +# If pipeline not triggered by tag and web-frontend code has changed: +# - Runs eslint and stylelint +# - Stores a web-frontend_lint_success file in the cache so future pipelines can skip +# if no file changes. +web-frontend-lint: + extends: + - .docker-image-test-stage + script: + - docker run --rm $WEBFRONTEND_CI_DEV_IMAGE lint + only: + changes: + - web-frontend/**/* + - premium/web-frontend/**/* + +# If pipeline not triggered by tag and web-frontend code has not changed: +# - If there is a previous successful lint run in the cache then skip. +# - otherwise runs lint and stores success file in cache if successful. +no-web-frontend-changes-so-try-skip-lint: + extends: + - web-frontend-lint + - .skippable-job + variables: + SKIP_JOB_NAME: web-frontend-lint + # Override inherited only block so we can run this job in the + # exact opposite situations. + only: null + except: + changes: + - web-frontend/**/* + - premium/web-frontend/**/* + +# If pipeline not triggered by tag and web-frontend code has changed: +# - Runs the web-frontend tests +# - Generates coverage and testing reports +# - Stores the reports in the cache if successful +web-frontend-test: + extends: + - .docker-image-test-stage + script: + - mkdir reports/ -p + - TEST_TYPE=$([[ "$ENABLE_COVERAGE" = "true" ]] && echo "ci-test" || echo "test") + - | + docker run --name=webfrontend_test $WEBFRONTEND_CI_DEV_IMAGE $TEST_TYPE \ + | tee reports/stdout.txt; + - docker cp webfrontend_test:/baserow/reports . + - docker rm webfrontend_test + only: + # Skip testing on if no change to web-frontend files + changes: + - web-frontend/**/* + - premium/web-frontend/**/* + artifacts: + paths: + - reports/ + reports: + cobertura: reports/coverage/cobertura-coverage.xml + junit: reports/junit.xml + coverage: '/Lines\s*:\s*(\d+.?\d*)%/' + +# If pipeline not triggered by tag and web-frontend code has not changed: +# - If there is a previous successful webfrontend test run in the cache then skip and +# unpack its coverage reports. +# - Otherwise runs the tests, coverage reporting and stores in cache if successful +# as normal +no-web-frontend-changes-so-try-skip-tests: + extends: + - web-frontend-test + - .skippable-job + variables: + SKIP_JOB_NAME: web-frontend-test + DOWNLOAD_AND_UNPACK_ARTIFACTS_ON_SKIP: 'true' + # Override inherited only block so we can run this job in the + # exact opposite situations. + only: null + except: + changes: + - web-frontend/**/* + - premium/web-frontend/**/* + +# If pipeline not triggered by tag: +# - Build and store non-dev images in CI repo under the `ci-tested` tag so we know +# those images have passed the tests. +build-final-web-frontend-image: + extends: .build-final-baserow-image + variables: + IMAGE_NAME: $WEBFRONTEND_IMAGE_NAME + DEV_IMAGE_NAME: $WEBFRONTEND_DEV_IMAGE_NAME + DOCKERFILE_PATH: $WEBFRONTEND_DOCKERFILE_PATH + + +# ================================== TRIGGER SAAS ===================================== + +# Triggers a special pipeline in dependant project and passes various variables to it. +# Only on master and develop. +trigger-saas-build: + stage: publish + inherit: + variables: + - CI_COMMIT_BRANCH + - TESTED_BACKEND_CI_IMAGE + - TESTED_WEBFRONTEND_CI_IMAGE + - CI_COMMIT_SHA + - CI_COMMIT_SHORT_SHA + - DEVELOP_BRANCH_NAME + - MASTER_BRANCH_NAME + variables: + UPSTREAM_SHA: $CI_COMMIT_SHA + UPSTREAM_SHORT_SHA: $CI_COMMIT_SHORT_SHA + UPSTREAM_TESTED_BACKEND_CI_IMAGE: $TESTED_BACKEND_CI_IMAGE + UPSTREAM_TESTED_WEBFRONTEND_CI_IMAGE: $TESTED_WEBFRONTEND_CI_IMAGE + only: + changes: + - web-frontend/**/* + - premium/web-frontend/**/* + - backend/**/* + - premium/backend/**/* + variables: + - ($CI_COMMIT_BRANCH == $DEVELOP_BRANCH_NAME || $CI_COMMIT_BRANCH == $MASTER_BRANCH_NAME) + allow_failure: true + trigger: + project: bramw/baserow-saas + branch: $CI_COMMIT_BRANCH + +# ================================== PUSHING BACKEND ================================== + +# Push baserow/backend:develop_latest +publish-backend-develop-latest-image: + extends: .publish-baserow-image + only: + variables: + - $CI_COMMIT_BRANCH == $DEVELOP_BRANCH_NAME + variables: + SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH: $DEVELOP_BRANCH_NAME + SOURCE_IMAGE: $TESTED_BACKEND_CI_IMAGE + TARGET_IMAGE: "$RELEASE_IMAGE_REPO/$BACKEND_IMAGE_NAME:$DEVELOP_LATEST_TAG" + TARGET_REGISTRY: $CI_REGISTRY + TARGET_REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD + TARGET_REGISTRY_USER: $CI_REGISTRY_USER + + +# Push baserow/backend_dev:develop_latest +publish-backend-develop-latest-dev-image: + extends: .publish-baserow-image + only: + variables: + - $CI_COMMIT_BRANCH == $DEVELOP_BRANCH_NAME + variables: + SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH: $DEVELOP_BRANCH_NAME + SOURCE_IMAGE: $TESTED_BACKEND_CI_DEV_IMAGE + TARGET_IMAGE: "$RELEASE_IMAGE_REPO/$BACKEND_DEV_IMAGE_NAME:$DEVELOP_LATEST_TAG" + TARGET_REGISTRY: $CI_REGISTRY + TARGET_REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD + TARGET_REGISTRY_USER: $CI_REGISTRY_USER + +# Push baserow/backend:$VERSION_GIT_TAG +publish-backend-release-tagged-image: + extends: .publish-baserow-image + only: + variables: + - $CI_COMMIT_TAG + variables: + SKIP_IF_TAG_NOT_ON_BRANCH: $MASTER_BRANCH_NAME + SOURCE_IMAGE: $TESTED_BACKEND_CI_IMAGE + TARGET_IMAGE: "$RELEASE_IMAGE_REPO/$BACKEND_IMAGE_NAME:$CI_COMMIT_TAG" + TARGET_REGISTRY: $CI_REGISTRY + TARGET_REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD + TARGET_REGISTRY_USER: $CI_REGISTRY_USER + +# Push baserow/backend:latest +publish-backend-latest-release-image: + extends: .publish-baserow-image + only: + variables: + - $CI_COMMIT_TAG + variables: + SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH: $MASTER_BRANCH_NAME + SKIP_IF_TAG_NOT_ON_BRANCH: $MASTER_BRANCH_NAME + SOURCE_IMAGE: $TESTED_BACKEND_CI_IMAGE + TARGET_IMAGE: "$RELEASE_IMAGE_REPO/$BACKEND_IMAGE_NAME:latest" + TARGET_REGISTRY: $CI_REGISTRY + TARGET_REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD + TARGET_REGISTRY_USER: $CI_REGISTRY_USER + +# ================================ PUSHING WEB-FRONTEND =============================== + +# Push baserow/web-frontend:develop_latest +publish-webfrontend-develop-latest-image: + extends: .publish-baserow-image + only: + variables: + - $CI_COMMIT_BRANCH == $DEVELOP_BRANCH_NAME + variables: + SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH: $DEVELOP_BRANCH_NAME + SOURCE_IMAGE: $TESTED_WEBFRONTEND_CI_IMAGE + TARGET_IMAGE: "$RELEASE_IMAGE_REPO/$WEBFRONTEND_IMAGE_NAME:$DEVELOP_LATEST_TAG" + TARGET_REGISTRY: $CI_REGISTRY + TARGET_REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD + TARGET_REGISTRY_USER: $CI_REGISTRY_USER + +# Push baserow/web-frontend_dev:develop_latest +publish-webfrontend-develop-latest-dev-image: + extends: .publish-baserow-image + only: + variables: + - $CI_COMMIT_BRANCH == $DEVELOP_BRANCH_NAME + variables: + SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH: $DEVELOP_BRANCH_NAME + SOURCE_IMAGE: $TESTED_WEBFRONTEND_CI_DEV_IMAGE + TARGET_IMAGE: "$RELEASE_IMAGE_REPO/$WEBFRONTEND_DEV_IMAGE_NAME:$DEVELOP_LATEST_TAG" + TARGET_REGISTRY: $CI_REGISTRY + TARGET_REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD + TARGET_REGISTRY_USER: $CI_REGISTRY_USER + +# Push baserow/web-frontend:$VERSION_GIT_TAG +publish-webfrontend-release-tagged-image: + extends: .publish-baserow-image + only: + variables: + - $CI_COMMIT_TAG + variables: + SKIP_IF_TAG_NOT_ON_BRANCH: $MASTER_BRANCH_NAME + SOURCE_IMAGE: $TESTED_WEBFRONTEND_CI_IMAGE + TARGET_IMAGE: "$RELEASE_IMAGE_REPO/$WEBFRONTEND_IMAGE_NAME:$CI_COMMIT_TAG" + TARGET_REGISTRY: $CI_REGISTRY + TARGET_REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD + TARGET_REGISTRY_USER: $CI_REGISTRY_USER + +# Push baserow/web-frontend:latest +publish-webfrontend-latest-release-image: + extends: .publish-baserow-image + only: + variables: + - $CI_COMMIT_TAG + variables: + SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH: $MASTER_BRANCH_NAME + SKIP_IF_TAG_NOT_ON_BRANCH: $MASTER_BRANCH_NAME + SOURCE_IMAGE: $TESTED_WEBFRONTEND_CI_IMAGE + TARGET_IMAGE: "$RELEASE_IMAGE_REPO/$WEBFRONTEND_IMAGE_NAME:latest" + TARGET_REGISTRY: $CI_REGISTRY + TARGET_REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD + TARGET_REGISTRY_USER: $CI_REGISTRY_USER diff --git a/.gitlab/ci_includes/jobs.yml b/.gitlab/ci_includes/jobs.yml new file mode 100644 index 000000000..65be55a99 --- /dev/null +++ b/.gitlab/ci_includes/jobs.yml @@ -0,0 +1,409 @@ +# ============== "Abstract" ci stages used by real stages ======================= + +# Builds a dev version of a specific Dockerfile (--target dev) using a previous CI +# image or the latest develop image as a cache to speed up the build. Tags and pushes +# the resulting dev image for later stages in the pipeline to use. +# +# To extend this stage set the DOCKERFILE_PATH and IMAGE_NAME variables. +.build-baserow-image: + image: docker:20.10.12 + stage: build + interruptible: true + # Prevent rebuilds when tagging as all we want to do is tag and push the already built image + except: + refs: + - pipelines + variables: + - $CI_COMMIT_TAG + services: + - docker:20.10.12-dind + variables: + DOCKER_BUILDKIT: 1 + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_CERTDIR: "/certs" + IMAGE_LABELS: > + --label org.opencontainers.image.vendor=$CI_PROJECT_URL + --label org.opencontainers.image.authors=$CI_PROJECT_URL + --label org.opencontainers.image.revision=$CI_COMMIT_SHA + --label org.opencontainers.image.source=$CI_PROJECT_URL + --label org.opencontainers.image.documentation=$CI_PROJECT_URL + --label org.opencontainers.image.licenses=$CI_PROJECT_URL + --label org.opencontainers.image.url=$CI_PROJECT_URL + --label vcs-url=$CI_PROJECT_URL + --label com.gitlab.ci.user=$CI_SERVER_URL/$GITLAB_USER_LOGIN + --label com.gitlab.ci.email=$GITLAB_USER_EMAIL + --label com.gitlab.ci.tagorbranch=$CI_COMMIT_REF_NAME + --label com.gitlab.ci.pipelineurl=$CI_PIPELINE_URL + --label com.gitlab.ci.commiturl=$CI_PROJECT_URL/commit/$CI_COMMIT_SHA + --label com.gitlab.ci.cijoburl=$CI_JOB_URL + --label com.gitlab.ci.mrurl=$CI_PROJECT_URL/-/merge_requests/$CI_MERGE_REQUEST_ID + --label org.opencontainers.image.ref.name=$CI_IMAGE_REPO:$CI_COMMIT_REF_NAME + script: + - | + echo "$CI_REGISTRY_PASSWORD" | \ + docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin + if [[ -z "$DOCKERFILE_PATH" ]]; then + echo "Must provide DOCKERFILE_PATH as a job variable" 2>&1 + exit 1 + fi + if [[ -z "$DEV_IMAGE_NAME" ]]; then + echo "Must provide DEV_IMAGE_NAME as a job variable" 2>&1 + exit 1 + fi + + + # Try cache from this branches latest image, if not fall back to the latest + # develop image. + # Ensure we don't go over 128 char docker tag length limit + TRUNCATED_BRANCH_NAME=${CI_COMMIT_REF_NAME:0:100} + CI_DEV_LATEST_BRANCH_TAG=$CLEANUP_JOB_CI_TAG_PREFIX$TRUNCATED_BRANCH_NAME + + LATEST_CI_IMAGE="$CI_IMAGE_REPO/$DEV_IMAGE_NAME:$CI_DEV_LATEST_BRANCH_TAG" + # ===== 1. Try pull an image we can use to cache the build with ===== + + # First try the latest CI image for this branch + CACHE_IMAGE=$LATEST_CI_IMAGE + if ! docker pull $CACHE_IMAGE; then + + # If that didnt work try the latest dev image from develop + CACHE_IMAGE="$RELEASE_IMAGE_REPO/$DEV_IMAGE_NAME:$DEVELOP_LATEST_TAG"; + if ! docker pull $CACHE_IMAGE; then + CACHE_IMAGE="" + fi + fi + + EXTRA_BUILD_ARGS="" + if [[ -n "$CACHE_IMAGE" ]]; then + echo "Caching docker build from $CACHE_IMAGE"; + EXTRA_BUILD_ARGS="$EXTRA_BUILD_ARGS --cache-from $CACHE_IMAGE"; + else + echo "Couldn't find image to cache build using" + fi + + # This image tag is one that can be used by subsequent build steps, using the + # latest one might introduce race conditions with concurrent pipelines. Instead + # by using a simple name + sha we know we will be getting the right image later on + # and we can easily re-construct this image path also as $CI_COMMIT_SHORT_SHA is + # available in all stages. + CI_IMAGE_PATH=$CI_IMAGE_REPO/$DEV_IMAGE_NAME:$CLEANUP_JOB_CI_TAG_PREFIX$CI_COMMIT_SHORT_SHA + + # ===== 2. Build a dev image to be used in subsequent CI stages ===== + + if [[ -n "$BUILD_FROM_IMAGE" ]]; then + EXTRA_BUILD_ARGS="$EXTRA_BUILD_ARGS --build-arg FROM_IMAGE=$BUILD_FROM_IMAGE"; + echo "Building from $BUILD_FROM_IMAGE." + fi + + # * Use `--build-arg BUILDKIT_INLINE_CACHE=1` to ensure this image's itermediate + # layers will be cached so builds caching from this image can use those layers. + # * $CACHE_ARG is a --cache-from if we have an existing image that we can use + # to speed up this build. + # * Target the dev image as we want to run tests and linting in this image. + # * Tag as both the ci image for use in later stages and the latest ci image to + # cache any future ci pipeline runs. + docker build \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + $EXTRA_BUILD_ARGS \ + $IMAGE_LABELS \ + --target dev \ + --tag $CI_IMAGE_PATH \ + --tag $LATEST_CI_IMAGE \ + -f $DOCKERFILE_PATH .; + + # ===== 3. Push the CI image for the next stages and latest ci image cache ===== + + docker push $CI_IMAGE_PATH + docker push $LATEST_CI_IMAGE + +# Builds a non-dev (no docker build target provided) and fully labelled final image +# and tags and pushes the non-dev and dev images using $TESTED_IMAGE_PREFIX to mark +# them as being successfully tested for the publishing jobs to use. +# +# To extend this stage set the DOCKERFILE_PATH, IMAGE_NAME and DEV_IMAGE_NAME variables. +.build-final-baserow-image: + image: $CI_UTIL_IMAGE + stage: build-final + interruptible: true + # Prevent rebuilds when tagging as all we want to do is tag and push + except: + refs: + - pipelines + variables: + - $CI_COMMIT_TAG + services: + - docker:20.10.12-dind + variables: + DOCKER_BUILDKIT: 1 + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_CERTDIR: "/certs" + IMAGE_LABELS: > + --label org.opencontainers.image.vendor=$CI_PROJECT_URL + --label org.opencontainers.image.authors=$CI_PROJECT_URL + --label org.opencontainers.image.revision=$CI_COMMIT_SHA + --label org.opencontainers.image.source=$CI_PROJECT_URL + --label org.opencontainers.image.documentation=$CI_PROJECT_URL + --label org.opencontainers.image.licenses=$CI_PROJECT_URL + --label org.opencontainers.image.url=$CI_PROJECT_URL + --label vcs-url=$CI_PROJECT_URL + --label com.gitlab.ci.user=$CI_SERVER_URL/$GITLAB_USER_LOGIN + --label com.gitlab.ci.email=$GITLAB_USER_EMAIL + --label com.gitlab.ci.tagorbranch=$CI_COMMIT_REF_NAME + --label com.gitlab.ci.pipelineurl=$CI_PIPELINE_URL + --label com.gitlab.ci.commiturl=$CI_PROJECT_URL/commit/$CI_COMMIT_SHA + --label com.gitlab.ci.cijoburl=$CI_JOB_URL + --label com.gitlab.ci.mrurl=$CI_PROJECT_URL/-/merge_requests/$CI_MERGE_REQUEST_ID + --label org.opencontainers.image.ref.name=$RELEASE_IMAGE_REPO:$CI_COMMIT_REF_NAME + script: + - | + echo "$CI_REGISTRY_PASSWORD" | \ + docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin + if [[ -z "$DOCKERFILE_PATH" ]]; then + echo "Must provide DOCKERFILE_PATH as a job variable" 2>&1 + exit 1 + fi + if [[ -z "$IMAGE_NAME" ]]; then + echo "Must provide IMAGE_NAME as a job variable" 2>&1 + exit 1 + fi + if [[ -z "$DEV_IMAGE_NAME" ]]; then + echo "Must provide DEV_IMAGE_NAME as a job variable" 2>&1 + exit 1 + fi + + # ===== 1. Setup image metadata labels ===== + #Build date for opencontainers + #rfc 3339 date + BUILDDATE="'$(date '+%FT%T%z' | sed -E -n 's/(\+[0-9]{2})([0-9]{2})$/\1:\2/p')'" + IMAGE_LABELS="$IMAGE_LABELS --label org.opencontainers.image.created=$BUILDDATE" + IMAGE_LABELS="$IMAGE_LABELS --label build-date=$BUILDDATE" + # Description for opencontainers + BUILDTITLE="$(echo $CI_PROJECT_TITLE | tr " " "_")_$IMAGE_NAME" + IMAGE_LABELS="$IMAGE_LABELS --label org.opencontainers.image.title=$BUILDTITLE" + IMAGE_LABELS="$IMAGE_LABELS --label org.opencontainers.image.description=$BUILDTITLE" + + # ==== 2. Tag, build and push non-dev image ==== + + # Cache from the CI dev image to build the non dev image. + CI_IMAGE_PATH=$CI_IMAGE_REPO/$DEV_IMAGE_NAME:$CLEANUP_JOB_CI_TAG_PREFIX$CI_COMMIT_SHORT_SHA + + TRUNCATED_BRANCH_NAME=${CI_COMMIT_REF_NAME:0:100} + NON_DEV_CACHE_IMAGE=$CI_IMAGE_REPO/$IMAGE_NAME:$CLEANUP_JOB_CI_TAG_PREFIX$TRUNCATED_BRANCH_NAME + + TARGET_NON_DEV_IMAGE_PATH=$CI_IMAGE_REPO/$IMAGE_NAME:$TESTED_IMAGE_PREFIX$CI_COMMIT_SHORT_SHA + TARGET_DEV_IMAGE_PATH=$CI_IMAGE_REPO/$DEV_IMAGE_NAME:$TESTED_IMAGE_PREFIX$CI_COMMIT_SHORT_SHA + + docker pull $CI_IMAGE_PATH + + if ! docker pull $NON_DEV_CACHE_IMAGE ; then + echo "Failed to find non dev cache image $NON_DEV_CACHE_IMAGE..." + EXTRA_BUILD_ARGS=""; + else + echo "Caching from $NON_DEV_CACHE_IMAGE"; + EXTRA_BUILD_ARGS="--cache-from $NON_DEV_CACHE_IMAGE"; + fi + + if [[ -n "$BUILD_FROM_IMAGE" ]]; then + EXTRA_BUILD_ARGS="$EXTRA_BUILD_ARGS --build-arg FROM_IMAGE=$BUILD_FROM_IMAGE"; + IMAGE_LABELS="$IMAGE_LABELS --label built-from-image=$BUILD_FROM_IMAGE" + if docker pull "$BUILD_FROM_IMAGE"; then + BUILT_FROM_REVISION=$(docker inspect $BUILD_FROM_IMAGE | jq -r '.[0].Config.Labels["org.opencontainers.image.revision"]') + BUILT_FROM_COMMITURL=$(docker inspect $BUILD_FROM_IMAGE | jq -r '.[0].Config.Labels["com.gitlab.ci.commiturl"]') + BUILT_FROM_CIJOBURL=$(docker inspect $BUILD_FROM_IMAGE | jq -r '.[0].Config.Labels["com.gitlab.ci.cijoburl"]') + BUILT_FROM_MRURL=$(docker inspect $BUILD_FROM_IMAGE | jq -r '.[0].Config.Labels["com.gitlab.ci.mrurl"]') + BUILT_FROM_VCSURL=$(docker inspect $BUILD_FROM_IMAGE | jq -r '.[0].Config.Labels["vcs-url"]') + + IMAGE_LABELS="$IMAGE_LABELS --label built-from-revision=$BUILD_FROM_REVISION" + IMAGE_LABELS="$IMAGE_LABELS --label built-from-commiturl=$BUILD_FROM_COMMITURL" + IMAGE_LABELS="$IMAGE_LABELS --label built-from-cijoburl=$BUILD_FROM_CIJOBURL" + IMAGE_LABELS="$IMAGE_LABELS --label built-from-mrurl=$BUILD_FROM_MRURL" + IMAGE_LABELS="$IMAGE_LABELS --label built-from-vcsurl=$BUILD_FROM_VCSURL" + else + echo "Failed to pull build from image $BUILD_FROM_IMAGE, something has gone wrong" + exit 1 + fi + fi + + # Build the normal non-dev image with all the tags and labels. + docker build \ + --cache-from $CI_IMAGE_PATH \ + $EXTRA_BUILD_ARGS \ + $FORMATTEDTAGLIST \ + $IMAGE_LABELS \ + -t $TARGET_NON_DEV_IMAGE_PATH \ + -f $DOCKERFILE_PATH .; + docker push $TARGET_NON_DEV_IMAGE_PATH + + # Build the cache image with layer caching enabled. We don't enable it for the image above to reduce its size. + docker build \ + --cache-from $CI_IMAGE_PATH \ + $EXTRA_BUILD_ARGS \ + $IMAGE_LABELS \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + -t $NON_DEV_CACHE_IMAGE \ + -f $DOCKERFILE_PATH .; + docker push $NON_DEV_CACHE_IMAGE + + docker tag $CI_IMAGE_PATH $TARGET_DEV_IMAGE_PATH + docker push $TARGET_DEV_IMAGE_PATH + +# A simple docker based test job which does not run for a TAG pipeline and does not +# check out git. +.docker-image-test-stage: + stage: test + image: $CI_UTIL_IMAGE + interruptible: true + # Prevent rebuilds when tagging as all we want to do is tag and push + except: + refs: + - pipelines + variables: + - $CI_COMMIT_TAG + services: + - docker:20.10.12-dind + + +# Pushes $SOURCE_IMAGE to $TARGET_IMAGE using the $TARGET_REGISTRY_PASSWORD, +# $TARGET_REGISTRY_USER and $TARGET_REGISTRY credentials. +# +# Set $SKIP_IF_TAG_NOT_ON_BRANCH to make the job skip if the commit is not on +# the specified branch. Useful for TAG pipelines when $CI_COMMIT_BRANCH is not set +# and so we need to do some extra git work to figure out what branches this commit is +# on. +# +# Set $SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH to a branch name. If the job is not +# for a commit which is the latest on the specified branch name (for example due to +# someone re-running a pipeline for an old commit) this job will be skipped. +.publish-baserow-image: + image: $CI_UTIL_IMAGE + stage: publish + services: + - docker:20.10.12-dind + except: + refs: + - pipelines + variables: + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_CERTDIR: "/certs" + allow_failure: + # By exiting with this code we can skip this step without failing the build, + # but still fail if something else goes wrong. + exit_codes: 137 + script: + - | + if [[ -n "$SKIP_IF_TAG_NOT_ON_BRANCH" ]]; then + # Query for all the branches that this commit is part of. + curl -s --header "JOB-TOKEN: $CI_JOB_TOKEN" \ + "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/repository/commits/$CI_COMMIT_SHA/refs?type=branch" \ + -o this_commits_branches.json; + # Extract just the branch names from the json so we can assert it matches. + TAG_BRANCH_NAMES=$(cat this_commits_branches.json | jq -r ".[].name") + NUM_BRANCHES=$(cat this_commits_branches.json | jq length) + # Ensure the commit is only on master and no other branches, otherwise someone + # could checkout a master commit as a new branch and tag it to cause an image + # upload. + if [[ "$NUM_BRANCHES" != "1" || "$TAG_BRANCH_NAMES" != "$SKIP_IF_TAG_NOT_ON_BRANCH" ]]; then + echo "Tags should never be applied to non $SKIP_IF_TAG_NOT_ON_BRANCH branches!" 2>&1; + echo "Pipeline is running for tag: $CI_COMMIT_TAG which for a commit that only appears on $SKIP_IF_TAG_NOT_ON_BRANCH and no other branches." 2>&1; + echo "Instead this commit appears on $NUM_BRANCHES branches called $TAG_BRANCH_NAMES" 2>&1; + exit 1; + fi + fi + + if [[ -n "$SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH" ]]; then + LATEST_COMMIT_HASH=$(git rev-parse origin/$SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH) + HEAD_COMMIT_HASH=$CI_COMMIT_SHA + if [[ "$LATEST_COMMIT_HASH" != "$HEAD_COMMIT_HASH" ]]; then + echo "Pipeline is not running for latest commit on origin/$SKIP_IF_NOT_LATEST_COMMIT_ON_BRANCH"; + echo " which has commit $LATEST_COMMIT_HASH."; + echo "Instead pipeline is running on commit $HEAD_COMMIT_HASH, exitting as configured to do so in this situation..."; + exit 137; + fi + fi + + echo "$TARGET_REGISTRY_PASSWORD" | docker login -u "$TARGET_REGISTRY_USER" "$TARGET_REGISTRY" --password-stdin + + if ! docker pull $SOURCE_IMAGE; then + echo "Could not pull $SOURCE_IMAGE, has the build pipeline finished yet?" 2>&1; + exit 1 + fi + docker tag $SOURCE_IMAGE $TARGET_IMAGE + docker push $TARGET_IMAGE + +.skippable-job: + before_script: + - | + if [[ -z "$SKIP_JOB_NAME" ]]; then + echo "Must provide SKIP_JOB_NAME as a job variable" 2>&1 + exit 1 + fi + + if [[ "$ENABLE_JOB_SKIPPING" = "true" ]]; then + + try_download_latest_successful_artifacts_for_commit(){ + COMMIT_HASH=$1 + JOB_NAME=$2 + echo -e "\e[0Ksection_start:`date +%s`:$COMMIT_HASH$JOB_NAME[collapsed=true]\r\e[0KPrevious successful run check for $JOB_NAME and $COMMIT_HASH" + URL="https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/repository/commits/$COMMIT_HASH/statuses?name=$JOB_NAME" + COMMIT_GITLAB_JOBS=$(curl --header "PRIVATE-TOKEN: $PROJECT_READ_ONLY_API_TOKEN" $URL) + + if [[ "$COMMIT_GITLAB_JOBS" ]]; then + echo "Got these job statuses: $COMMIT_GITLAB_JOBS" + JOB_ID=$(echo $COMMIT_GITLAB_JOBS| jq "[.[] | select(.status == \"success\")][0].id") + # Check if JOB_ID is an integer (POSIX compliant way) + + if [ "$JOB_ID" -eq "$JOB_ID" ] 2> /dev/null; then + if [[ -n "$DOWNLOAD_AND_UNPACK_ARTIFACTS_ON_SKIP" ]] ; then + exit_code=0 + curl --fail --location --output artifacts.zip \ + --header "PRIVATE-TOKEN: $PROJECT_READ_ONLY_API_TOKEN" \ + "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/jobs/$JOB_ID/artifacts" \ + || exit_code=$?; + + if [ ${exit_code} -ne 0 ]; then + echo "Failed to get artifacts from successful run $JOB_ID" + else + unzip artifacts.zip || exit_code=$? + if [ ${exit_code} -ne 0 ]; then + echo "Failed to unzip artifacts" + else + if [[ -f "reports/stdout.txt" ]]; then + cat reports/stdout.txt; + fi + echo "Skipping $JOB_NAME as previous successful run for $COMMIT_HASH and it's artifacts were found." + exit 0; + fi + fi + + else + echo "Skipping $JOB_NAME as previous successful build for $COMMIT_HASH were found.". + exit 0; + fi + else + echo "Failed to find successful run of $JOB_NAME in $COMMIT_GITLAB_JOBS" + fi + else + echo "Failed to query gitlab for jobs"; + fi + echo -e "\e[0Ksection_end:`date +%s`:$COMMIT_HASH$JOB_NAME\r\e[0K" + } + + SECOND_PARENT_COMMIT=$(git rev-list -1 --merges ${CI_COMMIT_SHA}~1..${CI_COMMIT_SHA}) + if [[ -z "$SECOND_PARENT_COMMIT" ]] ; then + # If there is no second parent commit then there is only one parent commit + # and so we can safely look for its artifacts. + PREVIOUS_COMMIT_SHA=$(git rev-parse HEAD~1) + # Search for successful runs of either the normal job or this job itself + # for either this or previous commit. + try_download_latest_successful_artifacts_for_commit $CI_COMMIT_SHA $SKIP_JOB_NAME + try_download_latest_successful_artifacts_for_commit $CI_COMMIT_SHA $CI_JOB_NAME + try_download_latest_successful_artifacts_for_commit $PREVIOUS_COMMIT_SHA $SKIP_JOB_NAME + try_download_latest_successful_artifacts_for_commit $PREVIOUS_COMMIT_SHA $CI_JOB_NAME + echo "Actually running job as successful run for previous or this commit not found" + else + # There is a second (or more) parent commit meaning we should re-run this job + # as a merge has happened. + echo "Running full job as this is a merge commit." + fi + else + echo "Force running job regardless of previous runs." + fi diff --git a/.gitlab/ci_util_image/Dockerfile b/.gitlab/ci_util_image/Dockerfile new file mode 100644 index 000000000..fda7eea7b --- /dev/null +++ b/.gitlab/ci_util_image/Dockerfile @@ -0,0 +1,9 @@ +# A small helper image which has some useful tools pre-installed that are used by ci +# stages. By building our own little image it means every single ci job doesn't need +# to repeatedly re-install these tools when they run. +FROM docker:20.10.12 +ENV PYTHONUNBUFFERED=1 +RUN apk add --update --no-cache curl git jq python3 openssh-client && ln -sf python3 /usr/bin/python +RUN python3 -m ensurepip +RUN pip3 install --no-cache --upgrade pip setuptools +RUN mkdir /baserow && python3 -m venv /baserow/venv && . /baserow/venv/bin/activate && pip3 install coverage diff --git a/backend/.coveragerc b/backend/.coveragerc new file mode 100644 index 000000000..f552fd64f --- /dev/null +++ b/backend/.coveragerc @@ -0,0 +1,12 @@ +[run] +# Also required for gitlab MR coverage to be shown correctly. +relative_files = True +omit = + */generated/* +# We can't set source as it changes the xml reports file paths to be relative from +# say `backend/src` instead of the root of the repo. Gitlab needs paths to be relative +# from the root so instead we just set include which ensures in gitlab MR coverage is +# shown correctly. +include = + backend/src/**/* + premium/backend/src/**/* diff --git a/backend/.test_durations b/backend/.test_durations new file mode 100644 index 000000000..d89937c31 --- /dev/null +++ b/backend/.test_durations @@ -0,0 +1,1140 @@ +{ + "baserow_premium/admin/dashboard/test_admin_dashboard_handler.py::test_get_active_user_counts": 0.1822943090046465, + "baserow_premium/admin/dashboard/test_admin_dashboard_handler.py::test_get_active_users_per_day": 0.16566099500050768, + "baserow_premium/admin/dashboard/test_admin_dashboard_handler.py::test_get_new_user_counts": 0.8151876599986281, + "baserow_premium/admin/dashboard/test_admin_dashboard_handler.py::test_get_new_users_per_day": 0.4079730240009667, + "baserow_premium/admin/groups/test_groups_admin_handler.py::test_cant_delete_template_group": 0.07579601500037825, + "baserow_premium/admin/groups/test_groups_admin_handler.py::test_delete_group": 0.21693506900192006, + "baserow_premium/admin/groups/test_groups_admin_handler.py::test_delete_group_without_premium_license": 0.11121500800072681, + "baserow_premium/admin/users/test_user_admin_handler.py::test_admin_can_deactive_and_unstaff_other_users": 0.1647288540007139, + "baserow_premium/admin/users/test_user_admin_handler.py::test_admin_can_delete_user": 0.11796121900260914, + "baserow_premium/admin/users/test_user_admin_handler.py::test_admin_can_modify_allowed_user_attributes": 0.16221829300411628, + "baserow_premium/admin/users/test_user_admin_handler.py::test_admin_cant_deactivate_themselves": 0.0576791929997853, + "baserow_premium/admin/users/test_user_admin_handler.py::test_admin_cant_delete_themselves": 0.06128557300326065, + "baserow_premium/admin/users/test_user_admin_handler.py::test_admin_cant_destaff_themselves": 0.057741159998840885, + "baserow_premium/admin/users/test_user_admin_handler.py::test_admin_delete_user_without_premium_license": 0.0577257209988602, + "baserow_premium/admin/users/test_user_admin_handler.py::test_admin_update_user_without_premium_license": 0.05568703899189131, + "baserow_premium/admin/users/test_user_admin_handler.py::test_non_admin_cant_delete_user": 0.06248184100331855, + "baserow_premium/admin/users/test_user_admin_handler.py::test_non_admin_cant_edit_user": 0.06459872799678124, + "baserow_premium/admin/users/test_user_admin_handler.py::test_raises_exception_when_deleting_an_unknown_user": 0.06124864099911065, + "baserow_premium/admin/users/test_user_admin_handler.py::test_raises_exception_when_updating_an_unknown_user": 0.06304805400213809, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_uses_djangos_built_in_smart_set_password": 0.1574360250015161, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_with_invalid_password_raises_error[984kds]": 0.1590474550066574, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_with_invalid_password_raises_error[Bgvmt95en6HGJZ9Xz0F8xysQ6eYgo2Y54YzRPxxv10b5n16F4rZ6YH4ulonocwiFK6970KiAxoYhULYA3JFDPIQGj5gMZZl25M46sO810Zd3nyBg699a2TDMJdHG7hAAi0YeDnuHuabyBawnb4962OQ1OOf1MxzFyNWG7NR2X6MZQL5G1V61x56lQTXbvK1AG1IPM87bQ3YAtIBtGT2vK3Wd83q3he5ezMtUfzK2ibj0WWhf86DyQB4EHRUJjYcBiI78iEJv5hcu33X2I345YosO66cTBWK45SqJEDudrCOq]": 0.15665854400140233, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_with_invalid_password_raises_error[]": 0.16137919500033604, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_with_invalid_password_raises_error[a]": 0.16080309500466683, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_with_invalid_password_raises_error[ab]": 0.1593808799989347, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_with_invalid_password_raises_error[ask]": 0.15975657799936016, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_with_invalid_password_raises_error[dsfkjh4]": 0.16153580999889527, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_with_invalid_password_raises_error[dsj43]": 0.15873133999775746, + "baserow_premium/admin/users/test_user_admin_handler.py::test_updating_a_users_password_with_invalid_password_raises_error[oiue]": 0.16811270299876924, + "baserow_premium/api/admin/dashboard/test_admin_dashboard_views.py::test_admin_dashboard": 0.14857133199984673, + "baserow_premium/api/admin/groups/test_groups_admin_views.py::test_cant_delete_template_group": 0.0693339899989951, + "baserow_premium/api/admin/groups/test_groups_admin_views.py::test_delete_group": 0.13029559099959442, + "baserow_premium/api/admin/groups/test_groups_admin_views.py::test_list_admin_groups": 0.1384509010022157, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_accessing_invalid_user_admin_page_returns_error": 0.06374025500190328, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_accessing_user_admin_with_invalid_page_size_returns_error": 0.06178190499849734, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_can_delete_user": 0.12688089400035096, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_can_patch_user": 0.12753979300396168, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_can_patch_user_without_providing_password": 0.07300627000222448, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_can_search_users": 0.1170142089977162, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_can_see_admin_users_endpoint": 0.06700950199956424, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_can_sort_users": 0.11766191599963349, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_cannot_delete_user_without_premium_license": 0.11292251899794792, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_getting_view_users_only_runs_two_queries_instead_of_n": 1.135972041000059, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_list_users_without_premium_license": 0.05721638199975132, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_admin_with_invalid_token_cannot_see_admin_users": 0.05717548800021177, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_error_returned_when_invalid_field_supplied_to_edit": 0.05928290700467187, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_error_returned_when_updating_user_with_invalid_email": 0.06189783299851115, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_error_returned_when_valid_and_invalid_fields_supplied_to_edit": 0.06387469899345888, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_invalid_password_returns_400[984kds]": 0.1151537420009845, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_invalid_password_returns_400[a]": 0.11094330899504712, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_invalid_password_returns_400[ab]": 0.11288261199661065, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_invalid_password_returns_400[ask]": 0.11714549599855673, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_invalid_password_returns_400[dsfkjh4]": 0.11293282800033921, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_invalid_password_returns_400[dsj43]": 0.11079325600076118, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_invalid_password_returns_400[oiue]": 0.11494598199715256, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_non_admin_cannot_delete_user": 0.110916064997582, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_non_admin_cannot_patch_user": 0.06779227199876914, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_non_admin_cannot_patch_user_without_premium_license": 0.060885039001732366, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_non_admin_cannot_see_admin_users_endpoint": 0.06364982399827568, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_returns_error_response_if_blank_sorts_provided": 0.058435456001461716, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_returns_error_response_if_invalid_sort_direction_provided": 0.05867311000110931, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_returns_error_response_if_invalid_sort_field_provided": 0.06850142500115908, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_returns_error_response_if_invalid_sorts_mixed_with_valid_ones": 0.05885015500098234, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_returns_error_response_if_no_sorts_provided": 0.05864809400009108, + "baserow_premium/api/admin/users/test_users_admin_views.py::test_returns_error_response_if_sort_direction_not_provided": 0.06823474200064084, + "baserow_premium/api/export/test_premium_export_views.py::test_exporting_json_writes_file_to_storage": 0.17049703399970895, + "baserow_premium/api/export/test_premium_export_views.py::test_exporting_xml_writes_file_to_storage": 0.16273675900083617, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_add_user_to_license": 0.11681095599851687, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_check_license": 0.13599404199703713, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_delete_license": 0.11428986699684174, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_delete_user_from_license": 0.12179404199923738, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_fill_users_in_license": 0.11625386999730836, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_get_license": 0.13057594899873948, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_license_user_lookup": 0.1775878129992634, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_list_licenses": 0.35079707600016263, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_register_license": 0.15721870699780993, + "baserow_premium/api/license/test_premium_license_views.py::test_admin_remove_all_users": 0.11555949400280952, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_cant_make_a_blank_row_comment": 0.09096986599615775, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_cant_make_a_null_row_comment": 0.08153097399917897, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_cant_make_a_row_comment_greater_than_max_settings": 0.09377145000325982, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_cant_make_a_row_without_premium_license": 0.07498848799878033, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_getting_row_comments_executes_fixed_number_of_queries": 0.1664281069970457, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_perm_deleting_a_trashed_row_with_comments_cleans_up_the_rows": 0.14113137800450204, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_perm_deleting_a_trashed_table_with_comments_cleans_up_the_rows": 0.1899557190008636, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_row_comments_api_view": 0.15420178699787357, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_row_comments_api_view_without_premium_license": 0.07917400300357258, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_row_comments_cant_create_comments_in_invalid_row_in_table": 0.08498848399540293, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_row_comments_cant_create_comments_in_invalid_table": 0.06335438000314753, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_row_comments_cant_view_comments_for_invalid_row_in_table": 0.07971987300334149, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_row_comments_cant_view_comments_for_invalid_table": 0.06053732400323497, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_row_comments_users_cant_create_comments_for_table_they_are_not_in_group_for": 0.14230158600548748, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_row_comments_users_cant_view_comments_for_table_they_are_not_in_group_for": 0.13711942700319923, + "baserow_premium/api/row_comments/test_row_comments_views.py::test_trashing_the_row_returns_404_for_comments": 0.1395496759978414, + "baserow_premium/api/views/views/test_kanban_views.py::test_create_kanban_view": 0.13086866899902816, + "baserow_premium/api/views/views/test_kanban_views.py::test_create_kanban_view_invalid_card_cover_image_field": 0.2708426210010657, + "baserow_premium/api/views/views/test_kanban_views.py::test_list_all_invalid_select_option_parameter": 0.08849603699854924, + "baserow_premium/api/views/views/test_kanban_views.py::test_list_all_rows": 0.1030027640008484, + "baserow_premium/api/views/views/test_kanban_views.py::test_list_all_rows_with_limit_and_offset": 0.14826155999980983, + "baserow_premium/api/views/views/test_kanban_views.py::test_list_rows_include_field_options": 0.10348627199709881, + "baserow_premium/api/views/views/test_kanban_views.py::test_list_rows_invalid_parameters": 0.11130999800298014, + "baserow_premium/api/views/views/test_kanban_views.py::test_list_with_specific_select_options": 0.11143074400024489, + "baserow_premium/api/views/views/test_kanban_views.py::test_list_without_valid_premium_license": 0.09280392400251003, + "baserow_premium/api/views/views/test_kanban_views.py::test_patch_kanban_view_field_options": 0.08793423000679468, + "baserow_premium/api/views/views/test_kanban_views.py::test_update_kanban_view": 0.11505826400389196, + "baserow_premium/api/views/views/test_kanban_views.py::test_update_kanban_view_card_cover_image_field": 0.09101296600420028, + "baserow_premium/export/test_premium_export_types.py::test_can_export_every_interesting_different_field_to_json": 2.2952473090044805, + "baserow_premium/export/test_premium_export_types.py::test_can_export_every_interesting_different_field_to_xml": 2.2912878140014072, + "baserow_premium/export/test_premium_export_types.py::test_cannot_export_json_without_premium_license": 2.378322243996081, + "baserow_premium/export/test_premium_export_types.py::test_cannot_export_xml_without_premium_license": 2.2118516850023298, + "baserow_premium/export/test_premium_export_types.py::test_if_duplicate_field_names_json_export": 0.14931628300109878, + "baserow_premium/export/test_premium_export_types.py::test_if_xml_duplicate_name_and_value_are_escaped": 0.1222804070021084, + "baserow_premium/export/test_premium_export_utils.py::test_get_unique_name": 0.0008035999962885398, + "baserow_premium/export/test_premium_export_utils.py::test_safe_xml_tag_name": 0.0008034000020415988, + "baserow_premium/export/test_premium_export_utils.py::test_to_xml": 0.0007807870024407748, + "baserow_premium/license/test_license_handler.py::test_add_user_to_license": 0.6863466670001799, + "baserow_premium/license/test_license_handler.py::test_check_licenses_with_authority_check": 0.031040695001138374, + "baserow_premium/license/test_license_handler.py::test_check_licenses_without_authority_check": 0.23054841499833856, + "baserow_premium/license/test_license_handler.py::test_decode_license_with_valid_license": 0.0014293559979705606, + "baserow_premium/license/test_license_handler.py::test_fetch_license_status_in_production_mode": 0.007037198003672529, + "baserow_premium/license/test_license_handler.py::test_fetch_license_status_with_authority": 0.006806551002227934, + "baserow_premium/license/test_license_handler.py::test_fetch_license_status_with_authority_invalid_response": 0.01111569200293161, + "baserow_premium/license/test_license_handler.py::test_fetch_license_status_with_authority_unavailable": 0.013204257997131208, + "baserow_premium/license/test_license_handler.py::test_fill_remaining_seats_in_license": 0.713903380001284, + "baserow_premium/license/test_license_handler.py::test_get_public_key_debug": 0.0011557020006875973, + "baserow_premium/license/test_license_handler.py::test_get_public_key_production": 0.0010503039993636776, + "baserow_premium/license/test_license_handler.py::test_has_active_premium_license": 0.27259950500229024, + "baserow_premium/license/test_license_handler.py::test_invalid_signature_decode_license": 0.0015919720026431605, + "baserow_premium/license/test_license_handler.py::test_register_an_older_license": 0.07743426599699887, + "baserow_premium/license/test_license_handler.py::test_register_license": 0.16693839599611238, + "baserow_premium/license/test_license_handler.py::test_register_license_with_authority_check_does_not_exist": 0.0702758690022165, + "baserow_premium/license/test_license_handler.py::test_register_license_with_authority_check_instance_id_mismatch": 0.07028844399974332, + "baserow_premium/license/test_license_handler.py::test_register_license_with_authority_check_invalid": 0.07279425200249534, + "baserow_premium/license/test_license_handler.py::test_register_license_with_authority_check_ok": 0.08199809299549088, + "baserow_premium/license/test_license_handler.py::test_register_license_with_authority_check_updated": 0.07766329500373104, + "baserow_premium/license/test_license_handler.py::test_remove_all_users_from_license": 0.7410918209970987, + "baserow_premium/license/test_license_handler.py::test_remove_license": 0.17189667399725295, + "baserow_premium/license/test_license_handler.py::test_remove_user_from_license": 0.6866209510044428, + "baserow_premium/license/test_license_handler.py::test_unsupported_version_decode_license": 0.7651296020012524, + "baserow_premium/license/test_license_handler.py::test_upgrade_license_by_register": 0.0733719480012951, + "baserow_premium/license/test_license_models.py::test_premium_license_model_is_active": 0.06169771500208299, + "baserow_premium/license/test_license_models.py::test_premium_license_model_properties": 0.007191326996689895, + "baserow_premium/license/test_license_models.py::test_premium_license_model_save": 0.006248095000046305, + "baserow_premium/license/test_license_tasks.py::test_license_check": 0.005903237004531547, + "baserow_premium/premium/test_premium_installed.py::test_premium_app_installed": 0.004354035001597367, + "baserow_premium/row_comments/test_row_comments_handler.py::test_cant_create_comment_without_premium_license": 0.07543832300143549, + "baserow_premium/row_comments/test_row_comments_handler.py::test_cant_make_blank_comment_using_handler": 0.08603012200183002, + "baserow_premium/row_comments/test_row_comments_handler.py::test_cant_make_null_comment_using_handler": 0.0857561539960443, + "baserow_premium/row_comments/test_row_comments_handler.py::test_row_comment_created_signal_called": 0.6049891099974047, + "baserow_premium/views/test_premium_view_handler.py::test_get_rows_grouped_by_single_select_field": 0.06970030700176721, + "baserow_premium/views/test_premium_view_handler.py::test_get_rows_grouped_by_single_select_field_not_existing_options_are_null": 0.03846194300058414, + "baserow_premium/views/test_premium_view_handler.py::test_get_rows_grouped_by_single_select_field_with_empty_table": 0.023536557997431373, + "baserow_premium/views/test_premium_view_types.py::test_convert_card_cover_image_field_deleted": 0.09759637999377446, + "baserow_premium/views/test_premium_view_types.py::test_convert_card_cover_image_field_to_another": 0.10965998399842647, + "baserow_premium/views/test_premium_view_types.py::test_field_of_same_table_is_provided": 0.1111354280001251, + "baserow_premium/views/test_premium_view_types.py::test_import_export_kanban_view": 0.09074440199765377, + "baserow_premium/views/test_premium_view_types.py::test_newly_created_view": 0.09444661100496887, + "baserow_premium/ws/test_ws_row_comments_signals.py::test_row_comment_created": 0.6207814519984822, + "tests/baserow/api/applications/test_application_views.py::test_create_application": 0.08253989600416389, + "tests/baserow/api/applications/test_application_views.py::test_delete_application": 0.1228395360049035, + "tests/baserow/api/applications/test_application_views.py::test_get_application": 0.12910750700029894, + "tests/baserow/api/applications/test_application_views.py::test_list_applications": 0.10352716600027634, + "tests/baserow/api/applications/test_application_views.py::test_order_tables": 0.07749547599814832, + "tests/baserow/api/applications/test_application_views.py::test_update_application": 0.13171893800245016, + "tests/baserow/api/groups/test_group_invitation_views.py::test_accept_group_invitation": 0.1191657720009971, + "tests/baserow/api/groups/test_group_invitation_views.py::test_create_group_invitation": 0.26868016999651445, + "tests/baserow/api/groups/test_group_invitation_views.py::test_delete_group_invitation": 0.18169929400028195, + "tests/baserow/api/groups/test_group_invitation_views.py::test_get_group_invitation": 0.17149721499663428, + "tests/baserow/api/groups/test_group_invitation_views.py::test_get_group_invitation_by_token": 0.16495009099890012, + "tests/baserow/api/groups/test_group_invitation_views.py::test_list_group_invitations": 0.13785813600043184, + "tests/baserow/api/groups/test_group_invitation_views.py::test_reject_group_invitation": 0.12208356699920841, + "tests/baserow/api/groups/test_group_invitation_views.py::test_update_group_invitation": 0.17463189900081488, + "tests/baserow/api/groups/test_group_invitation_views.py::test_when_group_is_trashed_so_is_invitation": 0.08184512000298128, + "tests/baserow/api/groups/test_group_user_views.py::test_delete_group_user": 0.17158070399455028, + "tests/baserow/api/groups/test_group_user_views.py::test_if_group_trashed_then_group_user_is_trashed": 0.06964253499972983, + "tests/baserow/api/groups/test_group_user_views.py::test_list_group_users": 0.18270031200154335, + "tests/baserow/api/groups/test_group_user_views.py::test_update_group_user": 0.18032029099776992, + "tests/baserow/api/groups/test_group_views.py::test_create_group": 0.06588677600302617, + "tests/baserow/api/groups/test_group_views.py::test_delete_group": 0.12677222000274924, + "tests/baserow/api/groups/test_group_views.py::test_leave_group": 0.12791166999886627, + "tests/baserow/api/groups/test_group_views.py::test_list_groups": 0.06758564799383748, + "tests/baserow/api/groups/test_group_views.py::test_reorder_groups": 0.07037355799911893, + "tests/baserow/api/groups/test_group_views.py::test_trashed_group_not_returned_by_views": 0.06636974199864198, + "tests/baserow/api/groups/test_group_views.py::test_update_group": 0.12704573399969377, + "tests/baserow/api/settings/test_settings_views.py::test_get_instance_id": 0.11899857599564712, + "tests/baserow/api/settings/test_settings_views.py::test_get_settings": 0.009036937004566425, + "tests/baserow/api/settings/test_settings_views.py::test_update_settings": 0.12602239999978337, + "tests/baserow/api/templates/test_templates_views.py::test_install_template": 0.462049827001465, + "tests/baserow/api/templates/test_templates_views.py::test_list_templates": 0.014340325000375742, + "tests/baserow/api/test_api_authentication.py::test_authenticate": 0.23731841900007566, + "tests/baserow/api/test_api_decorators.py::test_accept_timezone": 0.001084759998775553, + "tests/baserow/api/test_api_decorators.py::test_allowed_includes": 0.0009654050008975901, + "tests/baserow/api/test_api_decorators.py::test_map_exceptions": 0.0012284290023671929, + "tests/baserow/api/test_api_decorators.py::test_validate_body": 0.0020403839989739936, + "tests/baserow/api/test_api_decorators.py::test_validate_body_and_query_parameters": 0.0022062870048102923, + "tests/baserow/api/test_api_decorators.py::test_validate_body_custom_fields": 0.002890814001148101, + "tests/baserow/api/test_api_decorators.py::test_validate_query_parameter": 0.0027183580023120157, + "tests/baserow/api/test_api_utils.py::test_get_serializer_class": 0.005554090996156447, + "tests/baserow/api/test_api_utils.py::test_map_exceptions": 0.000925599000765942, + "tests/baserow/api/test_api_utils.py::test_validate_data": 0.002161112002795562, + "tests/baserow/api/test_api_utils.py::test_validate_data_custom_fields": 0.001348544996290002, + "tests/baserow/api/test_redoc.py::test_can_generate_open_api_schema": 0.19589749099759501, + "tests/baserow/api/trash/test_trash_views.py::test_can_get_trash_contents_for_undeleted_app": 0.06667796199690201, + "tests/baserow/api/trash/test_trash_views.py::test_can_get_trash_contents_for_undeleted_group": 0.061934466000820976, + "tests/baserow/api/trash/test_trash_views.py::test_can_get_trash_structure": 0.10369971000545775, + "tests/baserow/api/trash/test_trash_views.py::test_can_restore_a_deleted_trash_item": 0.08941777600193745, + "tests/baserow/api/trash/test_trash_views.py::test_cant_delete_same_item_twice": 0.30694540300100925, + "tests/baserow/api/trash/test_trash_views.py::test_cant_restore_a_deleted_trash_item_if_not_in_group": 0.13111413899969193, + "tests/baserow/api/trash/test_trash_views.py::test_cant_restore_a_non_existent_trashed_item": 0.0591339109960245, + "tests/baserow/api/trash/test_trash_views.py::test_cant_restore_a_trash_item_marked_for_perm_deletion": 0.09776903300007689, + "tests/baserow/api/trash/test_trash_views.py::test_cant_restore_a_trashed_item_requiring_a_parent_id_without_providing_it": 0.09919143799561425, + "tests/baserow/api/trash/test_trash_views.py::test_cant_restore_a_trashed_item_with_a_missing_parent": 0.1017198509980517, + "tests/baserow/api/trash/test_trash_views.py::test_deleting_a_group_moves_it_to_the_trash_and_hides_it": 0.09199045100103831, + "tests/baserow/api/trash/test_trash_views.py::test_deleting_a_user_who_trashed_something_returns_null_user_who_trashed": 0.1454551460010407, + "tests/baserow/api/trash/test_trash_views.py::test_emptying_a_app_for_diff_group_returns_400": 0.06902873000217369, + "tests/baserow/api/trash/test_trash_views.py::test_emptying_a_non_existent_app_returns_404": 0.06312174699996831, + "tests/baserow/api/trash/test_trash_views.py::test_emptying_a_non_existent_group_returns_404": 0.06278058699899702, + "tests/baserow/api/trash/test_trash_views.py::test_emptying_a_trashed_app_marks_it_for_perm_deletion": 0.09275943600005121, + "tests/baserow/api/trash/test_trash_views.py::test_emptying_a_trashed_group_marks_it_for_perm_deletion": 0.0868952629971318, + "tests/baserow/api/trash/test_trash_views.py::test_getting_a_app_for_diff_group_returns_400": 0.06429758699960075, + "tests/baserow/api/trash/test_trash_views.py::test_getting_a_non_existent_app_returns_404": 0.06200900799740339, + "tests/baserow/api/trash/test_trash_views.py::test_getting_a_non_existent_group_returns_404": 0.05879779100359883, + "tests/baserow/api/trash/test_trash_views.py::test_restoring_an_item_which_doesnt_need_parent_id_with_one_returns_error": 0.07930594899880816, + "tests/baserow/api/trash/test_trash_views.py::test_user_cant_empty_trash_contents_for_group_they_are_not_a_member_of": 0.1365212029995746, + "tests/baserow/api/trash/test_trash_views.py::test_user_cant_get_trash_contents_for_group_they_are_not_a_member_of": 0.13619533100063563, + "tests/baserow/api/user_files/test_user_files_serializers.py::test_user_file_field": 0.06825027700324426, + "tests/baserow/api/user_files/test_user_files_views.py::test_upload_file": 0.09843332099626423, + "tests/baserow/api/user_files/test_user_files_views.py::test_upload_file_via_url": 0.07843205600147485, + "tests/baserow/api/user_files/test_user_files_views.py::test_upload_file_via_url_within_private_network": 0.06179113500547828, + "tests/baserow/api/users/test_token_auth.py::test_token_auth": 0.40702503899592557, + "tests/baserow/api/users/test_token_auth.py::test_token_refresh": 0.06361441300396109, + "tests/baserow/api/users/test_user_views.py::test_additional_user_data": 0.24153990400009206, + "tests/baserow/api/users/test_user_views.py::test_change_password": 0.42482345399912447, + "tests/baserow/api/users/test_user_views.py::test_create_user": 0.8124972599980538, + "tests/baserow/api/users/test_user_views.py::test_create_user_with_invitation": 0.13139000999581185, + "tests/baserow/api/users/test_user_views.py::test_create_user_with_template": 0.15704336899943883, + "tests/baserow/api/users/test_user_views.py::test_dashboard": 0.21875405199898523, + "tests/baserow/api/users/test_user_views.py::test_password_reset": 0.45837033900170354, + "tests/baserow/api/users/test_user_views.py::test_send_reset_password_email": 0.5758736329989915, + "tests/baserow/api/users/test_user_views.py::test_user_account": 0.07045094299610355, + "tests/baserow/contrib/database/api/export/test_export_views.py::test_exporting_csv_table_writes_file_to_storage": 0.1475635590031743, + "tests/baserow/contrib/database/api/export/test_export_views.py::test_exporting_csv_writes_file_to_storage": 0.26490028300031554, + "tests/baserow/contrib/database/api/export/test_export_views.py::test_exporting_missing_table_returns_error": 0.06254219900074531, + "tests/baserow/contrib/database/api/export/test_export_views.py::test_exporting_missing_view_returns_error": 0.07351541500247549, + "tests/baserow/contrib/database/api/export/test_export_views.py::test_exporting_table_without_permissions_returns_error": 0.13916019400130608, + "tests/baserow/contrib/database/api/export/test_export_views.py::test_exporting_view_which_isnt_for_table_returns_error": 0.09187659600138431, + "tests/baserow/contrib/database/api/export/test_export_views.py::test_getting_missing_export_job_returns_error": 0.06867379299728782, + "tests/baserow/contrib/database/api/export/test_export_views.py::test_getting_other_users_export_job_returns_error": 0.1406945069975336, + "tests/baserow/contrib/database/api/export/test_export_views.py::test_unknown_export_type_for_table_returns_error": 0.08280015499985893, + "tests/baserow/contrib/database/api/fields/dependencies/test_dependency_rebuilder.py::test_formula_fields_will_be_rebuilt_to_depend_on_each_other": 0.04199140799755696, + "tests/baserow/contrib/database/api/fields/dependencies/test_dependency_rebuilder.py::test_rebuilding_a_link_row_field_creates_dependencies_with_vias": 0.07181699300053879, + "tests/baserow/contrib/database/api/fields/dependencies/test_dependency_rebuilder.py::test_rebuilding_with_a_circular_ref_will_raise": 0.04362488100377959, + "tests/baserow/contrib/database/api/fields/dependencies/test_dependency_rebuilder.py::test_str_of_field_dependency_uniquely_identifies_it": 0.05699873800040223, + "tests/baserow/contrib/database/api/fields/dependencies/test_dependency_rebuilder.py::test_trashing_a_link_row_field_breaks_vias": 0.06546254599743406, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_can_add_model_with_fields_to_cache": 0.028044913000485394, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_can_get_model_via_cache": 0.02391596500092419, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_can_just_add_model_fields_to_cache": 0.03038870000455063, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_cannot_cache_trashed_field": 0.023679249996348517, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_field_cache_can_inherit_cache_from_another": 0.022658789002889534, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_field_cache_can_inherit_from_model": 0.02182538499982911, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_field_cache_does_no_database_lookup_for_cached_field": 0.020897279999189777, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_looking_up_field_by_name_not_in_cache_queries_to_get_specific_field": 0.022547369993844768, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_looking_up_missing_specific_field_does_query": 0.024398211000516312, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_looking_up_non_existent_field_returns_none_after_query": 0.025942121999833034, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_cache.py::test_looking_up_specific_field_which_does_not_exist_returns_none": 0.03746312800285523, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_dependency_handler.py::test_deep_circular_ref": 3.631787512993469, + "tests/baserow/contrib/database/api/fields/dependencies/test_field_dependency_handler.py::test_get_same_table_deps": 0.04581077900365926, + "tests/baserow/contrib/database/api/fields/dependencies/test_update_collector.py::test_can_add_fields_in_same_starting_table_with_row_filter": 0.02965537099953508, + "tests/baserow/contrib/database/api/fields/dependencies/test_update_collector.py::test_can_add_fields_with_update_statements_in_same_starting_table": 0.02821043700168957, + "tests/baserow/contrib/database/api/fields/dependencies/test_update_collector.py::test_can_only_trigger_update_for_rows_joined_to_a_starting_row_across_a_m2m": 0.19416962199829868, + "tests/baserow/contrib/database/api/fields/dependencies/test_update_collector.py::test_can_trigger_update_for_rows_joined_to_a_starting_row_across_a_m2m_and_back": 0.19686669899965636, + "tests/baserow/contrib/database/api/fields/dependencies/test_update_collector.py::test_update_statements_at_the_same_path_node_are_grouped_into_one": 0.19897947299614316, + "tests/baserow/contrib/database/api/fields/test_field_views.py::test_create_field": 0.1480092970014084, + "tests/baserow/contrib/database/api/fields/test_field_views.py::test_delete_field": 0.1856247819996497, + "tests/baserow/contrib/database/api/fields/test_field_views.py::test_get_field": 0.1564786169983563, + "tests/baserow/contrib/database/api/fields/test_field_views.py::test_list_fields": 0.15562909900108934, + "tests/baserow/contrib/database/api/fields/test_field_views.py::test_update_field": 0.3366920149928774, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_created_on_field_type": 0.13476659600200946, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_date_field_type": 0.14075946899538394, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_email_field_type": 0.16302842799996142, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_file_field_type": 0.3821038940004655, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_formula_field_type": 0.1440126439993037, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_last_modified_field_type": 0.2172387639984663, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_long_text_field_type": 0.17023809899910702, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_lookup_field_type": 0.5808620119969419, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_multiple_select_field_type": 0.4850003440005821, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_number_field_type": 0.20009806599409785, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_phone_number_field_type": 0.1590226070038625, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_text_field_type": 0.09298098300132551, + "tests/baserow/contrib/database/api/fields/test_field_views_types.py::test_url_field_type": 0.15982422600063728, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_altering_type_of_underlying_causes_type_update": 0.1628146459988784, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_altering_type_of_underlying_causes_type_update_nested": 0.22926719200404477, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_altering_value_of_referenced_field": 0.175672705998295, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_can_compare_date_and_text": 0.14620122800261015, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_can_set_number_of_decimal_places": 0.18296201600242057, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_can_type_a_valid_formula_field": 0.13454910700238543, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_can_type_an_invalid_formula_field": 0.125973055997747, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_cant_make_circular_reference": 0.1275375469995197, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_cant_make_self_reference": 0.08383525099998224, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_changing_name_of_referenced_field_by_formula": 0.1457219769981748, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_changing_type_of_reference_field_to_invalid_one_for_formula": 0.16212627200366114, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_changing_type_of_reference_field_to_valid_one_for_formula": 0.15590606899786508, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_deleting_underlying_causes_type_update_nested": 0.1954870769950503, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_deleting_underlying_causes_type_update_nested_after_update": 0.21761368800434866, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_referencing_single_select": 0.13943857599952025, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_trashing_child_field": 0.14949497900306596, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_trashing_creating_child_field": 0.21074864500042167, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_trashing_formula_field": 0.1467373969971959, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_trashing_renaming_child_field": 0.21886658400399028, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_trashing_restoring_child_field": 0.18458519800333306, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_trashing_row_changing_formula_restoring_row": 0.19343550199482706, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_type_endpoint_returns_error_for_bad_syntax": 0.1317748909968941, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_type_endpoint_returns_error_for_circular_reference": 0.12905616100033512, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_type_endpoint_returns_error_for_missing_field": 0.09792185100377537, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_type_endpoint_returns_error_for_missing_parameters": 0.12250422499710112, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_type_endpoint_returns_error_for_non_formula_field": 0.09061722999831545, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_type_endpoint_returns_error_for_self_reference": 0.10190203099773498, + "tests/baserow/contrib/database/api/fields/test_formula_views.py::test_type_endpoint_returns_error_if_not_permissioned_for_field": 0.1713761080027325, + "tests/baserow/contrib/database/api/rows/test_row_serializers.py::test_get_example_row_serializer_class": 0.004491002997383475, + "tests/baserow/contrib/database/api/rows/test_row_serializers.py::test_get_row_serializer_with_user_field_names": 2.441662647001067, + "tests/baserow/contrib/database/api/rows/test_row_serializers.py::test_get_table_serializer": 0.05116628499672515, + "tests/baserow/contrib/database/api/rows/test_row_views.py::test_create_empty_row_for_interesting_fields": 2.4490239119950274, + "tests/baserow/contrib/database/api/rows/test_row_views.py::test_create_row": 0.29529440099940985, + "tests/baserow/contrib/database/api/rows/test_row_views.py::test_delete_row": 0.17443420700146817, + "tests/baserow/contrib/database/api/rows/test_row_views.py::test_get_row": 0.141728389000491, + "tests/baserow/contrib/database/api/rows/test_row_views.py::test_list_rows": 0.3350494859951141, + "tests/baserow/contrib/database/api/rows/test_row_views.py::test_list_rows_returns_https_next_url": 0.16374159699989832, + "tests/baserow/contrib/database/api/rows/test_row_views.py::test_list_rows_with_attribute_names": 0.3217858050011273, + "tests/baserow/contrib/database/api/rows/test_row_views.py::test_move_row": 0.16662000799624366, + "tests/baserow/contrib/database/api/rows/test_row_views.py::test_update_row": 0.23137770999892382, + "tests/baserow/contrib/database/api/tables/test_table_views.py::test_create_table": 0.134581744998286, + "tests/baserow/contrib/database/api/tables/test_table_views.py::test_create_table_with_data": 0.2855748809961369, + "tests/baserow/contrib/database/api/tables/test_table_views.py::test_delete_table": 0.08686402400053339, + "tests/baserow/contrib/database/api/tables/test_table_views.py::test_get_database_application_with_tables": 0.08495705899986206, + "tests/baserow/contrib/database/api/tables/test_table_views.py::test_get_table": 0.09060510499330121, + "tests/baserow/contrib/database/api/tables/test_table_views.py::test_list_tables": 0.10171817599621136, + "tests/baserow/contrib/database/api/tables/test_table_views.py::test_order_tables": 0.09722899700136622, + "tests/baserow/contrib/database/api/tables/test_table_views.py::test_update_table": 0.08783515899995109, + "tests/baserow/contrib/database/api/tokens/test_token_views.py::test_create_token": 0.07867190500110155, + "tests/baserow/contrib/database/api/tokens/test_token_views.py::test_delete_token": 0.14079041600052733, + "tests/baserow/contrib/database/api/tokens/test_token_views.py::test_get_token": 0.1430730570027663, + "tests/baserow/contrib/database/api/tokens/test_token_views.py::test_list_tokens": 0.06720003300506505, + "tests/baserow/contrib/database/api/tokens/test_token_views.py::test_update_token": 0.1902480920034577, + "tests/baserow/contrib/database/api/views/form/test_form_view_views.py::test_create_form_view": 0.20258397699944908, + "tests/baserow/contrib/database/api/views/form/test_form_view_views.py::test_form_view_link_row_lookup_view": 0.2733425680016808, + "tests/baserow/contrib/database/api/views/form/test_form_view_views.py::test_meta_submit_form_view": 0.2692732080067799, + "tests/baserow/contrib/database/api/views/form/test_form_view_views.py::test_submit_form_view": 0.26396848899457837, + "tests/baserow/contrib/database/api/views/form/test_form_view_views.py::test_test_enable_form_view_file_field_options": 0.08749844599878998, + "tests/baserow/contrib/database/api/views/form/test_form_view_views.py::test_update_form_view": 0.210900057994877, + "tests/baserow/contrib/database/api/views/gallery/test_gallery_view_views.py::test_create_gallery_view": 0.0891224089973548, + "tests/baserow/contrib/database/api/views/gallery/test_gallery_view_views.py::test_create_gallery_view_invalid_card_card_cover_image_field": 0.10511221399792703, + "tests/baserow/contrib/database/api/views/gallery/test_gallery_view_views.py::test_list_rows": 0.16476365799826453, + "tests/baserow/contrib/database/api/views/gallery/test_gallery_view_views.py::test_list_rows_include_field_options": 0.10771367499910411, + "tests/baserow/contrib/database/api/views/gallery/test_gallery_view_views.py::test_patch_gallery_view_field_options": 0.09253393100152607, + "tests/baserow/contrib/database/api/views/gallery/test_gallery_view_views.py::test_update_gallery_view": 0.07893334800246521, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_anon_user_cant_get_info_about_a_non_public_grid_view": 0.07515704900652054, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_cannot_get_info_about_non_grid_view": 0.0775598850013921, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_cannot_get_info_about_trashed_grid_view": 0.075971287998982, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_create_grid_view": 0.10972058600236778, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_get_public_grid_view": 0.09831430700069177, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_grid_view_link_row_lookup_view": 0.7109714940015692, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_list_filtered_rows": 0.14801164999880712, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_list_rows": 0.2360160369935329, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_list_rows_include_field_options": 0.10739521499999682, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_list_rows_include_row_metadata": 0.10350224899957539, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_list_rows_public_doesnt_show_hidden_columns": 0.10406807000254048, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_list_rows_public_filters_by_visible_and_hidden_columns": 0.12023807599689462, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_list_rows_public_only_searches_by_visible_columns": 0.11662993299614755, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_list_rows_public_with_query_param_filter": 0.14344609799809405, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_list_rows_public_with_query_param_order": 0.22428822200163268, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_patch_grid_view_field_options": 0.15389443700041738, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_update_grid_view": 0.20268017899797997, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_user_in_same_group_can_get_info_about_a_non_public_grid_view": 0.08084305799638969, + "tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py::test_user_in_wrong_group_cant_get_info_about_a_non_public_grid_view": 0.12456008899971494, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_create_view_filter": 0.14537222699800623, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_create_view_sort": 0.18325927299883915, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_delete_view": 0.15172227699804353, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_delete_view_filter": 0.10696290399937425, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_delete_view_sort": 0.11403457599953981, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_get_link_row_filter_type_preload_values": 0.16057079700112808, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_get_view": 0.16730092799843987, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_get_view_field_options": 0.09921593299804954, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_get_view_filter": 0.11309163399710087, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_get_view_sort": 0.11562721699738177, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_list_view_filters": 0.11876866399688879, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_list_view_sortings": 0.12259314099719631, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_list_views": 0.12278038499789545, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_list_views_including_filters": 0.126608128000953, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_list_views_including_sortings": 0.11670814999888535, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_order_views": 0.10444455799733987, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_patch_view_field_options": 0.11464323900145246, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_rotate_slug": 0.09620847800033516, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_update_view_filter": 0.17680737499904353, + "tests/baserow/contrib/database/api/views/test_view_views.py::test_update_view_sort": 0.19296561699957238, + "tests/baserow/contrib/database/api/webhooks/test_webhook_serializers.py::test_invalid_urls[http://google.de:8a]": 0.0008866970019880682, + "tests/baserow/contrib/database/api/webhooks/test_webhook_serializers.py::test_invalid_urls[http://localhost:4000/endpoint]": 0.001069691999873612, + "tests/baserow/contrib/database/api/webhooks/test_webhook_serializers.py::test_invalid_urls[http://localhost]": 0.0017054639974958263, + "tests/baserow/contrib/database/api/webhooks/test_webhook_serializers.py::test_invalid_urls[https://192.168.172.1:4000]": 0.001939785997819854, + "tests/baserow/contrib/database/api/webhooks/test_webhook_serializers.py::test_valid_urls[http://google.de]": 0.040831563994288445, + "tests/baserow/contrib/database/api/webhooks/test_webhook_serializers.py::test_valid_urls[https://google.de]": 0.022984340001130477, + "tests/baserow/contrib/database/api/webhooks/test_webhook_serializers.py::test_valid_urls[https://heise.de/myendpoint]": 0.04889409800307476, + "tests/baserow/contrib/database/api/webhooks/test_webhook_views.py::test_create_webhooks": 1.2879868909985817, + "tests/baserow/contrib/database/api/webhooks/test_webhook_views.py::test_delete_webhook": 0.1737498170004983, + "tests/baserow/contrib/database/api/webhooks/test_webhook_views.py::test_get_webhook": 0.14007720600056928, + "tests/baserow/contrib/database/api/webhooks/test_webhook_views.py::test_list_webhooks": 0.15533950399549212, + "tests/baserow/contrib/database/api/webhooks/test_webhook_views.py::test_trigger_test_call": 0.14251925600183313, + "tests/baserow/contrib/database/api/webhooks/test_webhook_views.py::test_update_webhook": 0.29009156100073596, + "tests/baserow/contrib/database/db/test_db_schema.py::test_lenient_schema_editor": 0.004551785994408419, + "tests/baserow/contrib/database/export/test_export_handler.py::test_a_column_without_a_grid_view_option_has_an_option_made_and_is_exported": 0.10983220500202151, + "tests/baserow/contrib/database/export/test_export_handler.py::test_a_complete_export_job_which_has_expired_will_have_its_file_deleted": 0.579833221003355, + "tests/baserow/contrib/database/export/test_export_handler.py::test_a_pending_job_which_has_expired_will_be_cleaned_up": 0.17267014800017932, + "tests/baserow/contrib/database/export/test_export_handler.py::test_a_running_export_job_which_has_expired_will_be_stopped": 0.16619485699993675, + "tests/baserow/contrib/database/export/test_export_handler.py::test_adding_more_rows_doesnt_increase_number_of_queries_run": 0.3120753990006051, + "tests/baserow/contrib/database/export/test_export_handler.py::test_an_export_job_which_fails_will_be_marked_as_a_failed_job": 0.0742540610008291, + "tests/baserow/contrib/database/export/test_export_handler.py::test_attempting_to_export_a_table_for_a_type_which_doesnt_support_it_fails": 0.07688076999693294, + "tests/baserow/contrib/database/export/test_export_handler.py::test_attempting_to_export_a_view_for_a_type_which_doesnt_support_it_fails": 0.07160518299860996, + "tests/baserow/contrib/database/export/test_export_handler.py::test_can_export_csv_with_different_charsets": 8.76918447999924, + "tests/baserow/contrib/database/export/test_export_handler.py::test_can_export_csv_with_different_column_separators": 1.563400430000911, + "tests/baserow/contrib/database/export/test_export_handler.py::test_can_export_csv_without_header": 0.27060809600152425, + "tests/baserow/contrib/database/export/test_export_handler.py::test_can_export_every_interesting_different_field_to_csv": 2.377172832002543, + "tests/baserow/contrib/database/export/test_export_handler.py::test_columns_are_exported_by_order_then_field_id": 0.10840328999620397, + "tests/baserow/contrib/database/export/test_export_handler.py::test_creating_a_new_export_job_will_cancel_any_already_running_jobs_for_that_user": 0.12699116799922194, + "tests/baserow/contrib/database/export/test_export_handler.py::test_creating_job_with_view_that_is_not_in_the_table": 0.08320964399899822, + "tests/baserow/contrib/database/export/test_export_handler.py::test_csv_is_filtered_by_filters": 0.09953807700367179, + "tests/baserow/contrib/database/export/test_export_handler.py::test_csv_is_sorted_by_sorts": 0.1057687279972015, + "tests/baserow/contrib/database/export/test_export_handler.py::test_exporting_table_ignores_view_filters_sorts_hides": 0.09551877000194509, + "tests/baserow/contrib/database/export/test_export_handler.py::test_hidden_fields_are_excluded": 0.10250970199922449, + "tests/baserow/contrib/database/field/test_boolean_field_type.py::test_alter_boolean_field_column_type": 0.12137663600515225, + "tests/baserow/contrib/database/field/test_boolean_field_type.py::test_get_set_export_serialized_value_boolean_field": 0.024144502000126522, + "tests/baserow/contrib/database/field/test_created_on_field_type.py::test_created_on_field_type": 0.24812444300187053, + "tests/baserow/contrib/database/field/test_created_on_field_type.py::test_created_on_field_type_wrong_timezone": 0.07261885700063431, + "tests/baserow/contrib/database/field/test_created_on_field_type.py::test_import_export_last_modified_field": 0.1495540789946972, + "tests/baserow/contrib/database/field/test_date_field_type.py::test_converting_date_field_value": 0.6265088500003912, + "tests/baserow/contrib/database/field/test_date_field_type.py::test_date_field_type": 0.16364126499684062, + "tests/baserow/contrib/database/field/test_date_field_type.py::test_date_field_type_prepare_value": 0.02804522599763004, + "tests/baserow/contrib/database/field/test_date_field_type.py::test_get_set_export_serialized_value_date_field": 0.02986785100074485, + "tests/baserow/contrib/database/field/test_date_field_type.py::test_import_export_date_field": 0.02213132899851189, + "tests/baserow/contrib/database/field/test_date_field_type.py::test_negative_date_field_value": 0.13234241499958443, + "tests/baserow/contrib/database/field/test_field_converters.py::test_link_row_field_converter_applicable": 0.03300329500052612, + "tests/baserow/contrib/database/field/test_field_filters.py::test_building_filter_with_and_type_ands_all_provided_qs_together": 0.08177209099449101, + "tests/baserow/contrib/database/field/test_field_filters.py::test_building_filter_with_annotated_qs_annotates_prior_to_filter": 0.0819289259998186, + "tests/baserow/contrib/database/field/test_field_filters.py::test_building_filter_with_many_annotated_qs_merges_the_annotations": 0.0848865059997479, + "tests/baserow/contrib/database/field/test_field_filters.py::test_building_filter_with_or_type_ors_all_provided_qs_together": 0.08496238800216815, + "tests/baserow/contrib/database/field/test_field_filters.py::test_can_invert_an_annotated_q": 0.07781829900704906, + "tests/baserow/contrib/database/field/test_field_handler.py::test_can_convert_between_all_fields": 0.00021683700106223114, + "tests/baserow/contrib/database/field/test_field_handler.py::test_can_convert_formula_to_numeric_field": 0.10579274100018665, + "tests/baserow/contrib/database/field/test_field_handler.py::test_create_field": 0.19514646500101662, + "tests/baserow/contrib/database/field/test_field_handler.py::test_create_primary_field": 0.11009516000194708, + "tests/baserow/contrib/database/field/test_field_handler.py::test_delete_field": 0.1498028170026373, + "tests/baserow/contrib/database/field/test_field_handler.py::test_field_which_changes_its_underlying_type_will_have_alter_sql_run": 0.09431575999769848, + "tests/baserow/contrib/database/field/test_field_handler.py::test_find_next_free_field_name": 0.09337993999724858, + "tests/baserow/contrib/database/field/test_field_handler.py::test_find_next_free_field_name_returns_strings_with_max_length": 0.08598811599586043, + "tests/baserow/contrib/database/field/test_field_handler.py::test_get_field": 0.14203433299917378, + "tests/baserow/contrib/database/field/test_field_handler.py::test_just_changing_a_fields_name_will_not_run_alter_sql": 0.08866632200079039, + "tests/baserow/contrib/database/field/test_field_handler.py::test_update_field": 0.2711294740001904, + "tests/baserow/contrib/database/field/test_field_handler.py::test_update_field_failing": 0.0960010679991683, + "tests/baserow/contrib/database/field/test_field_handler.py::test_update_field_when_underlying_sql_type_doesnt_change": 0.09474686999965343, + "tests/baserow/contrib/database/field/test_field_handler.py::test_update_field_when_underlying_sql_type_doesnt_change_old_prep": 0.10109238799850573, + "tests/baserow/contrib/database/field/test_field_handler.py::test_update_field_when_underlying_sql_type_doesnt_change_with_vars": 0.10058151799967163, + "tests/baserow/contrib/database/field/test_field_handler.py::test_update_field_with_type_error_on_conversion_should_null_field": 0.09916723700007424, + "tests/baserow/contrib/database/field/test_field_handler.py::test_update_select_options": 0.1626256370000192, + "tests/baserow/contrib/database/field/test_field_handler.py::test_when_field_type_forces_same_type_alter_fields_alter_sql_is_run": 0.09917613599827746, + "tests/baserow/contrib/database/field/test_field_models.py::test_date_field_get_python_format": 0.00430670399509836, + "tests/baserow/contrib/database/field/test_field_models.py::test_link_row_field": 0.02406825999787543, + "tests/baserow/contrib/database/field/test_field_models.py::test_model_class_name": 0.029610636996949324, + "tests/baserow/contrib/database/field/test_field_types.py::test_email_field_type": 0.19724937800128828, + "tests/baserow/contrib/database/field/test_field_types.py::test_human_readable_values": 2.4816247329981707, + "tests/baserow/contrib/database/field/test_field_types.py::test_import_export_formula_field": 0.09371159299917053, + "tests/baserow/contrib/database/field/test_field_types.py::test_import_export_lookup_field": 0.25005603399768006, + "tests/baserow/contrib/database/field/test_field_types.py::test_import_export_text_field": 0.018126520000805613, + "tests/baserow/contrib/database/field/test_field_types.py::test_long_text_field_type": 0.1282892269991862, + "tests/baserow/contrib/database/field/test_field_types.py::test_phone_number_field_type": 0.23874165899906075, + "tests/baserow/contrib/database/field/test_field_types.py::test_valid_email": 0.2318102090030152, + "tests/baserow/contrib/database/field/test_field_types.py::test_valid_url": 0.27917843500108575, + "tests/baserow/contrib/database/field/test_file_field_type.py::test_file_field_type": 0.3630491420008184, + "tests/baserow/contrib/database/field/test_file_field_type.py::test_import_export_file_field": 0.14462564299901715, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_accessing_cached_internal_formula_second_time_does_no_queries": 0.10153150399855804, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_adding_a_formula_field_to_an_existing_table_populates_it_for_all_rows": 0.09579599299831898, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_all_functions_are_registered": 0.0039157699975476135, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_can_change_formula_type_breaking_other_fields": 0.14392171900180983, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_can_delete_double_link_lookup_field_value": 0.6320674550006515, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_can_delete_lookup_field_value": 0.34569244599697413, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_can_insert_and_update_rows_with_formula_referencing_single_select": 0.13613402400005725, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_can_rename_field_preserving_whitespace": 0.12186881999878096, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_can_still_insert_rows_with_an_invalid_but_previously_date_formula_field": 0.15406459500081837, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_can_update_lookup_field_value": 0.32714918200144893, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_can_use_complex_contains_filters_on_formula_field": 0.08978627500255243, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_can_use_complex_date_filters_on_formula_field": 0.08858395700008259, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_cannot_create_view_filter_or_sort_on_invalid_field": 0.4201982289996522, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_cant_change_the_value_of_a_formula_field_directly": 0.029709312999329995, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_changing_type_of_other_field_still_results_in_working_filter": 0.11439791700104252, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_creating_a_model_with_formula_field_immediately_populates_it": 0.027323898000759073, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_formula_with_row_id_is_populated_after_creating_row": 0.0940826410005684, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_get_set_export_serialized_value_formula_field": 0.027972527997917496, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_nested_lookup_with_formula": 0.41812684599790373, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_recalculate_formulas_according_to_version": 0.08361776099991403, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_recalculated_internal_type_with_incorrect_syntax_formula_sets_to_invalid": 0.1074197690031724, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_renaming_dependency_maintains_dependency_link": 0.12872540599710192, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_row_dependency_update_functions_do_no_row_updates_for_same_table": 0.11095411400674493, + "tests/baserow/contrib/database/field/test_formula_field_type.py::test_saving_after_properties_have_been_cached_does_recaclulation": 0.10173656799815944, + "tests/baserow/contrib/database/field/test_last_modified_field_type.py::test_import_export_last_modified_field": 0.1482895599983749, + "tests/baserow/contrib/database/field/test_last_modified_field_type.py::test_last_modified_field_type": 0.2690179360033653, + "tests/baserow/contrib/database/field/test_last_modified_field_type.py::test_last_modified_field_type_wrong_timezone": 0.07042218800052069, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_call_apps_registry_pending_operations": 0.12751273899993976, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_change_link_row_related_table_when_field_with_related_name_exists": 0.18322343299951172, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_change_type_to_link_row_field_when_field_with_same_related_name_already_exists": 0.23182258199813077, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_creating_a_linked_row_pointing_at_trashed_row_works_but_does_not_display": 0.2790179820040066, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_import_export_link_row_field": 0.2848040260032576, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_link_row_enhance_queryset": 0.2134044919985172, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_link_row_field_type": 0.6140818189960555, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_link_row_field_type_api_row_views": 0.5107156589947408, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_link_row_field_type_api_views": 0.35717486900102813, + "tests/baserow/contrib/database/field/test_link_row_field_type.py::test_link_row_field_type_rows": 0.3503738559993508, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_can_create_new_row_with_immediate_link_row_values_and_lookup_will_match": 0.26969507800095016, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_can_lookup_single_select": 0.2894474149979942, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_can_modify_row_containing_lookup": 0.415125123996404, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_can_set_sub_type_options_for_lookup_field": 0.24699362800311064, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_can_update_lookup_field_value": 0.31004207499790937, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_converting_away_from_lookup_field_deletes_parent_formula_field": 0.3008462889956718, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_deleting_related_link_row_field_dep_breaks_deps": 0.692901130001701, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_deleting_related_link_row_field_still_lets_you_create_edit_rows": 0.4997819170021103, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_deleting_related_table_still_lets_you_create_edit_rows": 0.5518457869984559, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_deleting_restoring_lookup_target_works": 0.516468169997097, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_deleting_table_with_dependants_works": 0.8865542860003188, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_import_export_lookup_field_trashed_target_field": 0.2851856960041914, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_import_export_lookup_field_when_through_field_trashed": 0.28283000500232447, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_import_export_tables_with_lookup_fields": 0.4309415409989015, + "tests/baserow/contrib/database/field/test_lookup_field_type.py::test_moving_a_looked_up_row_updates_the_order": 0.4074311019976449, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_call_apps_registry_pending_operations": 0.08815630100070848, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_date_to_multiple_select_field": 0.8899391160011874, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_email_to_multiple_select_field": 0.16493962600361556, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_multiple_select_to_single_select_field": 0.24401307399966754, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_number_to_multiple_select_field": 0.1677826209961495, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_single_select_to_multiple_select_field": 0.17410404199836194, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_to_multiple_select_field_with_select_options": 0.14145503300460405, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_to_multiple_select_with_more_than_threshold_options_in_extraction": 0.18497807899257168, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_to_multiple_select_with_more_than_threshold_options_provided": 0.17778510200150777, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_to_multiple_select_with_option_value_too_large": 0.12871136899775593, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_conversion_to_multiple_select_with_same_option_value_on_same_row": 0.12840830000277492, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_convert_long_text_to_multiple_select": 0.12787734100493253, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_convert_multiple_select_to_text": 0.15976367599796504, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_convert_multiple_select_to_text_with_comma_and_quotes": 0.36620113200115156, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_converting_multiple_select_field_value": 0.18431071499799145, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_get_set_export_serialized_value_multiple_select_field": 0.18926347600427107, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_import_export_multiple_select_field": 0.098541983999894, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_multi_select_enhance_queryset": 0.13481401999888476, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_multi_select_field_type": 0.1686954959986906, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_multiple_select_field_type_deleting_select_option": 0.20396548900316702, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_multiple_select_field_type_random_value": 0.12822240099922055, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_multiple_select_field_type_rows": 0.31332344399925205, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_multiple_select_field_type_sorting": 0.1885911820027104, + "tests/baserow/contrib/database/field/test_multiple_select_field_type.py::test_multiple_select_with_single_select_present": 0.12125386200204957, + "tests/baserow/contrib/database/field/test_number_field_type.py::test_alter_number_field_column_type[expected0-field_kwargs0]": 0.1142319230020803, + "tests/baserow/contrib/database/field/test_number_field_type.py::test_alter_number_field_column_type[expected1-field_kwargs1]": 0.10934832399652805, + "tests/baserow/contrib/database/field/test_number_field_type.py::test_alter_number_field_column_type[expected2-field_kwargs2]": 0.11313199500000337, + "tests/baserow/contrib/database/field/test_number_field_type.py::test_alter_number_field_column_type[expected3-field_kwargs3]": 0.10973676499997964, + "tests/baserow/contrib/database/field/test_number_field_type.py::test_alter_number_field_column_type_negative": 0.1140367860061815, + "tests/baserow/contrib/database/field/test_number_field_type.py::test_content_type_still_set_when_save_overridden": 0.0125199639951461, + "tests/baserow/contrib/database/field/test_number_field_type.py::test_import_export_number_field": 0.024261272003059275, + "tests/baserow/contrib/database/field/test_rating_field_type.py::test_field_creation": 0.13661165899975458, + "tests/baserow/contrib/database/field/test_rating_field_type.py::test_rating_field_modification": 0.37719987599848537, + "tests/baserow/contrib/database/field/test_rating_field_type.py::test_row_creation": 0.11954575200070394, + "tests/baserow/contrib/database/field/test_single_select_field_type.py::test_get_set_export_serialized_value_single_select_field": 0.11277724899991881, + "tests/baserow/contrib/database/field/test_single_select_field_type.py::test_import_export_single_select_field": 0.09259393200045452, + "tests/baserow/contrib/database/field/test_single_select_field_type.py::test_primary_single_select_field_with_link_row_field": 0.30158197099444806, + "tests/baserow/contrib/database/field/test_single_select_field_type.py::test_single_select_field_type": 0.16515628299748641, + "tests/baserow/contrib/database/field/test_single_select_field_type.py::test_single_select_field_type_api_row_views": 0.18490051399567164, + "tests/baserow/contrib/database/field/test_single_select_field_type.py::test_single_select_field_type_api_views": 0.2133135609983583, + "tests/baserow/contrib/database/field/test_single_select_field_type.py::test_single_select_field_type_get_order": 0.12853297599576763, + "tests/baserow/contrib/database/field/test_single_select_field_type.py::test_single_select_field_type_random_value": 0.11747650199686177, + "tests/baserow/contrib/database/field/test_single_select_field_type.py::test_single_select_field_type_rows": 0.30128350199811393, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas['a' + 2-ERROR_WITH_FORMULA-Error with formula: argument number 2 given to operator + was of type number but the only usable types for this argument are text,char.]": 0.08201323300454533, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas['a' < 1-ERROR_WITH_FORMULA-None]": 0.08076972400158411, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas['a' > 1-ERROR_WITH_FORMULA-None]": 0.0879280920016754, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas['t'/1-ERROR_WITH_FORMULA-None]": 0.07796206100101699, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[1/'t'-ERROR_WITH_FORMULA-None]": 0.07786832300189417, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[10/LOWER(1)-ERROR_WITH_FORMULA-None]": 0.08022280800287263, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[CONCAT('a')-ERROR_WITH_FORMULA-Error with formula: 1 argument was given to the function concat, it must instead be given more than 1 arguments.]": 0.09131320400047116, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[CONCAT('test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test','test')-ERROR_WITH_FORMULA-Error with formula: it exceeded the maximum formula size.]": 4.091613471995515, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[CONCAT()-ERROR_WITH_FORMULA-Error with formula: 0 arguments were given to the function concat, it must instead be given more than 1 arguments.]": 0.08824853400074062, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[LOWER('a', CONCAT())-ERROR_WITH_FORMULA-None]": 0.08390476999920793, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[LOWER('a','a')-ERROR_WITH_FORMULA-None]": 0.07685991800462944, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[LOWER()-ERROR_WITH_FORMULA-None]": 0.08320808899952681, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[LOWER(1)-ERROR_WITH_FORMULA-None]": 0.08432201200048439, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[LOWER(1,2)-ERROR_WITH_FORMULA-None]": 0.08332277699446422, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[UPPER('a','a')-ERROR_WITH_FORMULA-Error with formula: 2 arguments were given to the function upper, it must instead be given exactly 1 argument.]": 0.07582142499813926, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[UPPER('ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt')-ERROR_WITH_FORMULA-Error with formula: an embedded string in the formula over the maximum length of 10000 .]": 0.13463028399200994, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[UPPER()-ERROR_WITH_FORMULA-None]": 0.08495423199929064, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[UPPER(1)-ERROR_WITH_FORMULA-None]": 0.08191172200167784, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[UPPER(1,2)-ERROR_WITH_FORMULA-None]": 0.08261589799803915, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER('test'))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))-ERROR_WITH_FORMULA-Error with formula: it exceeded the maximum formula size.]": 0.15821069600133342, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[concat(upper(1), lower('a'))-ERROR_WITH_FORMULA-Error with formula: argument number 1 given to function upper was of type number but the only usable type for this argument is text.]": 0.08718186099940795, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[concat(upper(1), lower(2))-ERROR_WITH_FORMULA-Error with formula: argument number 1 given to function upper was of type number but the only usable type for this argument is text, argument number 1 given to function lower was of type number but the only usable type for this argument is text.]": 0.08318980500189355, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[date_interval('1 second') - todate('20210101', 'YYYYMMDD')-ERROR_WITH_FORMULA-Error with formula: argument number 2 given to operator - was of type date but the only usable type for this argument is date_interval.]": 0.08228327100005117, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[field(9999)-ERROR_WITH_FORMULA-None]": 0.07631486300306278, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[field_by_id(9999)-ERROR_WITH_FORMULA-None]": 0.07760962700194796, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[left(\"aa\", 2.0)-ERROR_WITH_FORMULA-Error with formula: argument number 2 given to function left was of type number but the only usable type for this argument is a whole number with no decimal places.]": 0.08826549600053113, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[test-ERROR_WITH_FORMULA-Error with formula: Invalid syntax at line 1, col 4: mismatched input 'the end of the formula' expecting '('.]": 0.07700468900657143, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[todate('20200101', 'YYYYMMDD') + todate('20210101', 'YYYYMMDD')-ERROR_WITH_FORMULA-Error with formula: argument number 2 given to operator + was of type date but the only usable type for this argument is date_interval.]": 0.08027843400122947, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[true + true-ERROR_WITH_FORMULA-Error with formula: argument number 2 given to operator + was of type boolean but there are no possible types usable here.]": 0.08577649899962125, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[true < 1-ERROR_WITH_FORMULA-None]": 0.0781028849996801, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[true < true-ERROR_WITH_FORMULA-None]": 0.07751027999984217, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[true > 1-ERROR_WITH_FORMULA-None]": 0.08784594700409798, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[true > true-ERROR_WITH_FORMULA-None]": 0.08255601399650914, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_invalid_formulas[upper(1)-ERROR_WITH_FORMULA-Error with formula: argument number 1 given to function upper was of type number but the only usable type for this argument is text.]": 0.08410495399948559, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_complex_formulas[Can compare a date field and text with formatting-table_setup5-field('date')='02/01/2020'-expected5]": 0.12743714400130557, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_complex_formulas[Can compare a datetime field and text with eu formatting-table_setup6-field('date')='01/02/2020 00:10'-expected6]": 0.12154822399679688, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_complex_formulas[Can compare a phone number and number column-table_setup4-field('pn')=field('num')-expected4]": 0.13421183699756511, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_complex_formulas[Can reference and add to a integer column-table_setup0-field('number')+1-expected0]": 0.12443297700156108, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_complex_formulas[Can reference and add to a integer column-table_setup1-formula1-expected1]": 0.16069794099530554, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_complex_formulas[Can reference and if a phone number column-table_setup3-if(field('pn')='01772', field('pn'), 'no')-expected3]": 0.13931113299986464, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_complex_formulas[Can reference and if a text column-table_setup2-if(field('text')='a', field('text'), 'no')-expected2]": 0.13067427800342557, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_complex_formulas[Can use a boolean field in an if-table_setup8-if(field('boolean'), 'true', 'false')-expected8]": 0.1216375540025183, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_complex_formulas[Can use datediff on fields-table_setup7-date_diff('dd', field('date1'), field('date2'))-expected7]": 0.13383440800316748, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas['a' != 'a'-False]": 0.1062882019978133, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas['a' != 'b'-True]": 0.10903012700146064, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas['a' + 'b'-ab]": 0.1067711700052314, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas['a' = 'a'-True]": 0.11368777099778526, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas['https://\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923.\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e'-https://\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923.\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e]": 0.12104071100111469, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas['test'-test]": 0.11210431500148843, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[(10+2)/3-4.00000]": 0.10908921800364624, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[1 != '1'-False]": 0.11507346500366111, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[1 < 1-False]": 0.10402749199420214, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[1 <= 1-True]": 0.10682173399982275, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[1 = '1'-True]": 0.11593784999786294, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[1 > 1-False]": 0.11208833400087315, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[1 >= 1-True]": 0.10831602499456494, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[1+1-2]": 0.10988701799942646, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[1.2 * 2-2.4]": 0.11465475799923297, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[1/0-NaN]": 0.1133969229995273, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[10+10/2-15.00000]": 0.11450348400103394, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[10/3-3.33333]": 0.11177391299497685, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999+1-NaN]": 0.11298072000136017, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[CONCAT('\\ntest', '\\n')-\\ntest\\n]": 0.11598091199994087, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[CONCAT('a',2)-a2]": 0.11336335099622374, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[CONCAT('https://\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923.\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e', '/api')-https://\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923.\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e/api]": 0.11935978299879935, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[CONCAT('test', ' ', 'works')-test works]": 0.1190215359965805, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[CONCAT('test', ' ', UPPER('works'))-test WORKS]": 0.12155885599713656, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[CONCAT(1,2)-12]": 0.11216460900323, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[IF('a' = 'a', 'a', 'b')-a]": 0.11073115399995004, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[IF('a' = 'a', 1, 'b')-1]": 0.11894079299963778, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[IF('a' = 'b', 'a', 'b')-b]": 0.12077074400076526, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[IF('a' = 'b', 1, 'b')-b]": 0.1187796719968901, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[LOWER('HTTPS://\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923.\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e')-https://\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923.\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e]": 0.12034835100712371, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[LOWER('TEST')-test]": 0.11419117599871242, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[LOWER(UPPER('test'))-test0]": 0.11505560200021137, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[LOWER(UPPER('test'))-test1]": 0.11276711000027717, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[UPPER('https://\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923.\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e')-HTTPS://\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923.\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e]": 0.12067559799834271, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[UPPER('test')-TEST]": 0.10989955900367931, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[UPPER('tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt')-TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT]": 0.25287549199856585, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER('test'))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))-TEST]": 0.2082099359977292, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[and(false, false)-False]": 0.10378225300155464, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[and(false, true)-False]": 0.10665248700024677, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[and(true, false)-False]": 0.10745526399841765, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[and(true, true)-True]": 0.22854292599731707, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[contains('a', '')-True]": 0.10984974700113526, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[contains('a', 'a')-True]": 0.10923289699712768, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[contains('a', 'x')-False]": 0.10868266200486687, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[date_diff('incorrect thingy', todate('20200101', 'YYYYMMDD'), todate('20100101', 'YYYYMMDD'))-NaN]": 0.11771761400086689, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[date_diff('yy', todate('20200101', 'YYYYMMDD'), todate('20100101', 'YYYYMMDD'))--10]": 0.12757109599988325, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[date_interval('1 invalid')-None]": 0.10157239699765341, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[date_interval('1 year') + todate('20200101', 'YYYYMMDD')-2021-01-01]": 0.10603540799638722, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[date_interval('1 year') - date_interval('1 day')-364 00:00:00]": 0.1057595099991886, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[date_interval('1 year') > date_interval('1 day')-True]": 0.1042274979990907, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[date_interval('1 year')-365 00:00:00]": 0.10298462200080394, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[day(todate('20170103','YYYYMMDD'))-3]": 0.11253356100132805, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[false-False]": 0.1018244520018925, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[if(1=1, todate('20200101', 'YYYYMMDD'), 'other')-2020-01-01]": 0.11342093999701319, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[isblank(' ')-False]": 0.10739556400221772, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[isblank('')-True]": 0.11607571999775246, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[isblank(1)-False]": 0.10387523700046586, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[left('a', 2)-a]": 0.11078108799847541, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[left('abc', 2)-ab]": 0.10756220700204722, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[length('')-0]": 0.11168174899648875, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[length('aaa')-3]": 0.11397990000114078, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[month(todate('20200601', 'YYYYMMDD') + ( todate('20200601', 'YYYYMMDD') - todate('20100601', 'YYYYMMDD')))-6]": 0.11475207900366513, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[month(todate('20200601', 'YYYYMMDD') - date_interval('1 year'))-6]": 0.11823849500069628, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[not(false)-True]": 0.1051166489996831, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[not(isblank('')) != false-False]": 0.10985311300100875, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[not(isblank(tonumber('x')))-True]": 0.11019155899703037, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[not(true)-False]": 0.11035125899798004, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[or(false, false)-False]": 0.10709749400120927, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[or(false, true)-True]": 0.10417946799861966, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[or(true, false)-True]": 0.12151641399759683, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[or(true, true)-True]": 0.10284679299365962, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[replace('test test', 'test', 'a')-a a]": 0.10865276700133109, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[reverse('abc')-cba]": 0.1063330569959362, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[search('a', 'test')-0]": 0.115229568000359, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[search('test test', 'test')-1]": 0.10516063200338976, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[t('aaaa')-aaaa]": 0.10914124499686295, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[t(10)-]": 0.11277913200319745, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[todate('20170103','YYYYMMDD')-2017-01-03]": 0.10424006200264557, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[todate('20200101', 'YYYYMMDD') + date_interval('1 second')-2020-01-01]": 0.111843475002388, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[todate('20200101', 'YYYYMMDD') + date_interval('1 year')-2021-01-01]": 0.10473916999762878, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[todate('20200101', 'YYYYMMDD') - date_interval('1 year')-2019-01-01]": 0.11581243299588095, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[todate('20200101', 'YYYYMMDD') - todate('20210101', 'YYYYMMDD')--366 00:00:00]": 0.10784475899708923, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[todate('blah', 'YYYY')-None]": 0.10603165800057468, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[tonumber('-12.12345')--12.12345]": 0.10617485900002066, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[tonumber('1')-1.00000]": 0.10467058199719759, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[tonumber('9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999')+1-NaN]": 0.11670924200370791, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[tonumber('a')-NaN]": 0.1153073269961169, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[totext(1)-1]": 0.11517395399641828, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[totext(date_interval('1 year'))-1 year]": 0.11136929199710721, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[totext(todate('20200101', 'YYYYMMDD'))-2020-01-01]": 0.10935914499714272, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[totext(true)-true]": 0.1172862029998214, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[true != false-True]": 0.12019277800209238, + "tests/baserow/contrib/database/formula/test_baserow_formula_results.py::test_valid_formulas[true-True]": 0.10275806700155954, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_can_replace_multiple_different_field_references": 0.001647215998673346, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_doesnt_replace_unknown_field": 0.0017137809954874683, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_leaves_unknown_field_references_along": 0.0010523679993639234, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_raises_with_field_names_for_invalid_syntax": 0.002293820998602314, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replace_binary_op_keeping_whitespace_and_comments": 0.0016060899979493115, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replace_double_quote_field_ref_containing_double_quotes": 0.0011282510022283532, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replace_double_quote_field_ref_containing_single_quotes": 0.0012293309991946444, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replace_double_quoted_field_ref": 0.001569961998029612, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replace_field_reference_keeping_whitespace": 0.0013439150025078561, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replace_field_reference_keeping_whitespace_and_comments": 0.003069377999054268, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replace_field_reference_preserving_case": 0.002361950999329565, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replace_function_call_keeping_whitespace_and_comments": 0.002520005000405945, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replace_single_quoted_field_ref": 0.0012374360012472607, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_field_with_double_quotes_with_id": 0.0011474460006866138, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_field_with_field_by_id": 0.001015320001897635, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_field_with_single_quotes_with_id": 0.00107702399691334, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_functions_preserving_case": 0.0016700990017852746, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_known_field_by_id": 0.0016032340026868042, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_known_field_by_id_double_quotes": 0.0011712220002664253, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_known_field_by_id_single_quotes": 0.0010206580045633018, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_lookup": 0.0013575820012192708, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_lookup_when_via_changes": 0.0016018900059862062, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_unknown_field_by_id_with_field": 0.0010275710010319017, + "tests/baserow/contrib/database/formula/test_rename_field_references.py::test_replaces_unknown_field_by_id_with_field_multiple": 0.0016595489978499245, + "tests/baserow/contrib/database/management/test_copy_tables.py::test_a_batch_size_one_more_than_the_number_of_tables_runs_two_batches": 0.0008161240002664272, + "tests/baserow/contrib/database/management/test_copy_tables.py::test_a_batch_size_the_same_as_the_number_of_tables_runs_one_batch": 0.0009660159994382411, + "tests/baserow/contrib/database/management/test_copy_tables.py::test_a_batch_with_some_tables_ignored_wont_merge_with_the_next_batch": 0.0009234880017174874, + "tests/baserow/contrib/database/management/test_copy_tables.py::test_a_table_already_in_the_target_db_is_not_in_the_command": 0.0011664720041153487, + "tests/baserow/contrib/database/management/test_copy_tables.py::test_the_final_batch_includes_all_remaining_tables": 0.0010268910009472165, + "tests/baserow/contrib/database/management/test_fill_table.py::test_fill_table_fields": 0.2998870849951345, + "tests/baserow/contrib/database/management/test_fill_table.py::test_fill_table_fields_with_add_all_fields": 0.713565963000292, + "tests/baserow/contrib/database/management/test_fill_table.py::test_fill_table_rows_empty_table[10]": 0.0964451600011671, + "tests/baserow/contrib/database/management/test_fill_table.py::test_fill_table_rows_empty_table[5]": 0.1014231170011044, + "tests/baserow/contrib/database/management/test_fill_table.py::test_fill_table_rows_no_empty_table[10]": 0.10293895499853534, + "tests/baserow/contrib/database/management/test_fill_table.py::test_fill_table_rows_no_empty_table[5]": 0.09829056799935643, + "tests/baserow/contrib/database/management/test_fill_table.py::test_fill_table_rows_no_table": 0.008522109001205536, + "tests/baserow/contrib/database/migrations/test_add_and_move_public_flags.py::test_backwards_migration": 3.1577742480039888, + "tests/baserow/contrib/database/migrations/test_add_and_move_public_flags.py::test_forwards_migration": 2.8628256830015744, + "tests/baserow/contrib/database/migrations/test_add_and_move_public_flags.py::test_multi_batch_forwards_migration": 2.9341845120034122, + "tests/baserow/contrib/database/migrations/test_field_dependencies_migration.py::test_backwards_migration": 4.245335350002279, + "tests/baserow/contrib/database/migrations/test_field_dependencies_migration.py::test_forwards_migration": 4.306943578998471, + "tests/baserow/contrib/database/migrations/test_fix_hanging_formula_fields_migration.py::test_forwards_migration": 0.9581023899991123, + "tests/baserow/contrib/database/migrations/test_fixed_trashed_field_dependencies_migration.py::test_forwards_migration": 2.4234628300037, + "tests/baserow/contrib/database/migrations/test_remove_field_by_id_migration.py::test_backwards_migration": 5.444408576997375, + "tests/baserow/contrib/database/migrations/test_remove_field_by_id_migration.py::test_forwards_migration": 3.445366104999266, + "tests/baserow/contrib/database/migrations/test_remove_multiselect_missing_options.py::test_forwards_migration": 3.1921899219996703, + "tests/baserow/contrib/database/migrations/test_unique_field_names_migration.py::test_backwards_migration_restores_field_names": 6.176184419997298, + "tests/baserow/contrib/database/migrations/test_unique_field_names_migration.py::test_migration_fixes_duplicate_field_names": 6.594768871000269, + "tests/baserow/contrib/database/migrations/test_unique_field_names_migration.py::test_migration_fixes_duplicate_field_names_and_reserved_names": 6.420055753998895, + "tests/baserow/contrib/database/migrations/test_unique_field_names_migration.py::test_migration_handles_existing_fields_with_underscore_number": 6.339773437000986, + "tests/baserow/contrib/database/rows/test_row_metadata_registry.py::test_merges_together_row_metadata_by_type_and_row_id": 0.0008679029997438192, + "tests/baserow/contrib/database/rows/test_row_metadata_registry.py::test_nothing_registered_returns_empty_even_when_rows_provided": 0.000804121998953633, + "tests/baserow/contrib/database/rows/test_row_webhook_event_types.py::test_row_created_event_type": 0.08264526299899444, + "tests/baserow/contrib/database/rows/test_row_webhook_event_types.py::test_row_deleted_event_type": 0.08038528300312464, + "tests/baserow/contrib/database/rows/test_row_webhook_event_types.py::test_row_updated_event_type": 0.08047714499844005, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_create_row": 0.22676620500715217, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_delete_row": 0.15482597499794792, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_extract_field_ids_from_string": 0.0008105529959721025, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_extract_manytomany_values": 0.005149810996954329, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_get_field_ids_from_dict": 0.0008451880057691596, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_get_include_exclude_fields": 0.039844130998972105, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_get_include_exclude_fields_with_user_field_names": 0.04050452400042559, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_get_row": 0.15074964200539398, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_has_row": 0.14967846799845574, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_move_row": 0.14469994999672053, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_restore_row": 0.11673740199694294, + "tests/baserow/contrib/database/rows/test_rows_handler.py::test_update_row": 0.1610925219974888, + "tests/baserow/contrib/database/table/test_table_handler.py::test_create_database_table": 0.14213519999975688, + "tests/baserow/contrib/database/table/test_table_handler.py::test_delete_database_table": 0.12141560500094783, + "tests/baserow/contrib/database/table/test_table_handler.py::test_deleting_a_table_breaks_dependant_fields_and_sends_updates_for_them": 0.23267239599954337, + "tests/baserow/contrib/database/table/test_table_handler.py::test_deleting_table_trashes_all_fields_and_any_related_links": 0.4298572179977782, + "tests/baserow/contrib/database/table/test_table_handler.py::test_fill_example_table_data": 0.12220887600051356, + "tests/baserow/contrib/database/table/test_table_handler.py::test_fill_table_with_initial_data": 0.20778561899714987, + "tests/baserow/contrib/database/table/test_table_handler.py::test_get_database_table": 0.09148263200040674, + "tests/baserow/contrib/database/table/test_table_handler.py::test_order_tables": 0.14100845199936884, + "tests/baserow/contrib/database/table/test_table_handler.py::test_restoring_a_table_restores_fields_and_related_fields": 0.27646440700118546, + "tests/baserow/contrib/database/table/test_table_handler.py::test_restoring_table_with_a_previously_trashed_field_leaves_the_field_trashed": 0.28070958700118354, + "tests/baserow/contrib/database/table/test_table_handler.py::test_update_database_table": 0.11693661699609947, + "tests/baserow/contrib/database/table/test_table_models.py::test_enhance_by_fields_queryset": 0.025518204001855338, + "tests/baserow/contrib/database/table/test_table_models.py::test_filter_by_fields_object_queryset": 0.05008161600198946, + "tests/baserow/contrib/database/table/test_table_models.py::test_get_table_model": 0.059990449000906665, + "tests/baserow/contrib/database/table/test_table_models.py::test_get_table_model_to_str": 0.0344297949995962, + "tests/baserow/contrib/database/table/test_table_models.py::test_group_user_get_next_order": 0.026181412002188154, + "tests/baserow/contrib/database/table/test_table_models.py::test_order_by_fields_string_queryset": 0.1170088120015862, + "tests/baserow/contrib/database/table/test_table_models.py::test_order_by_fields_string_queryset_with_user_field_names": 0.07260285500160535, + "tests/baserow/contrib/database/table/test_table_models.py::test_search_all_fields_queryset": 0.10530895199917722, + "tests/baserow/contrib/database/table/test_table_models.py::test_table_model_fields_requiring_refresh_after_update": 0.0297694959990622, + "tests/baserow/contrib/database/table/test_table_models.py::test_table_model_fields_requiring_refresh_on_insert": 0.03742265000255429, + "tests/baserow/contrib/database/test_database_application_type.py::test_import_export_database": 0.11238028699881397, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_check_table_permissions": 0.30097156299234484, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_create_token": 0.12326924700391828, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_delete_token": 0.12920054599817377, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_generate_token": 0.09770301499884226, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_get_by_key": 0.11236546300642658, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_get_token": 0.12579134000043268, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_has_table_permission": 0.3343288210016908, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_rotate_token_key": 0.1184437390002131, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_update_token": 0.11541600900090998, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_update_token_permission": 0.13706440900205052, + "tests/baserow/contrib/database/tokens/test_token_handler.py::test_update_token_usage": 0.08018560899654403, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_a_parent_id_must_be_provided_when_trashing_or_restoring_a_row": 0.09285493100469466, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_a_parent_id_must_not_be_provided_when_trashing_or_restoring_an_app": 0.06718578300569789, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_a_restored_field_will_have_its_name_changed_to_ensure_it_is_unique": 0.42537707800147473, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_a_trashed_linked_row_pointing_at_a_trashed_row_is_restored_correctly": 0.32061351199808996, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_can_delete_applications_and_rows_in_the_same_perm_delete_batch": 0.14902877699933015, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_can_delete_fields_and_rows_in_the_same_perm_delete_batch": 0.16786849900017842, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_can_delete_tables_and_rows_in_the_same_perm_delete_batch": 0.1534726900026726, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_can_perm_delete_tables": 0.7289579179996508, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_can_trash_row_with_blank_primary_file_field": 0.08432986000116216, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_can_trash_row_with_blank_primary_single_select": 0.08373118199961027, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_cant_delete_row_perm_without_tableid": 0.0977955269991071, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_delete_row": 0.09474416200464475, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_delete_row_perm": 0.0997067700009211, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_perm_delete_field": 0.09878361500159372, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_perm_delete_link_row_field": 0.21709899300185498, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_perm_delete_lookup_row_field": 0.3758315589984704, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_perm_delete_related_link_row_field": 0.2054349390018615, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_perm_delete_table": 0.08311656799924094, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_perm_delete_table_and_related_link_row_field": 0.27435808700101916, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_perm_deleting_many_rows_at_once_only_looks_up_the_model_once": 0.12027008099903469, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_restoring_a_trashed_link_field_restores_the_opposing_field_also": 0.21864359700339264, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_trashed_row_entry_extra_description_is_unnamed_when_no_value_pk": 0.08541731299919775, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_trashed_row_entry_includes_the_rows_primary_key_value_as_an_extra_description": 0.08891813199807075, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_trashing_a_field_with_a_filter_trashes_the_filter": 0.12962901299761143, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_trashing_a_field_with_a_sort_trashes_the_sort": 0.12813068699688301, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_trashing_a_row_hides_it_from_a_link_row_field_pointing_at_it": 0.2680312769989541, + "tests/baserow/contrib/database/trash/test_database_trash_types.py::test_trashing_a_table_with_link_fields_pointing_at_it_also_trashes_those_fields": 0.23726034899664228, + "tests/baserow/contrib/database/view/test_view_filters.py::test_boolean_filter_type": 0.09314264400018146, + "tests/baserow/contrib/database/view/test_view_filters.py::test_can_mix_field_types_and_callables_in_compatible_field_types": 0.03465879499708535, + "tests/baserow/contrib/database/view/test_view_filters.py::test_can_use_a_callable_in_compatible_field_types": 0.039806060995033477, + "tests/baserow/contrib/database/view/test_view_filters.py::test_contains_filter_type": 0.2006056910031475, + "tests/baserow/contrib/database/view/test_view_filters.py::test_contains_not_filter_type": 0.17195546099901549, + "tests/baserow/contrib/database/view/test_view_filters.py::test_date_after_filter_type": 0.0821279189985944, + "tests/baserow/contrib/database/view/test_view_filters.py::test_date_before_filter_type": 0.0921225649981352, + "tests/baserow/contrib/database/view/test_view_filters.py::test_date_day_month_year_filter_type": 0.11131056300655473, + "tests/baserow/contrib/database/view/test_view_filters.py::test_date_equal_filter_type": 0.10212339400095516, + "tests/baserow/contrib/database/view/test_view_filters.py::test_date_equals_day_of_month_filter_type": 0.12242770699958783, + "tests/baserow/contrib/database/view/test_view_filters.py::test_date_not_equal_filter_type": 0.10831390800012741, + "tests/baserow/contrib/database/view/test_view_filters.py::test_date_parser_mixin": 0.000857010996696772, + "tests/baserow/contrib/database/view/test_view_filters.py::test_empty_filter_type": 0.3042519769987848, + "tests/baserow/contrib/database/view/test_view_filters.py::test_equal_filter_type": 0.11842489399714395, + "tests/baserow/contrib/database/view/test_view_filters.py::test_filename_contains_filter_type": 0.09886952799934079, + "tests/baserow/contrib/database/view/test_view_filters.py::test_has_file_type": 0.08774609100146336, + "tests/baserow/contrib/database/view/test_view_filters.py::test_higher_than_filter_type": 0.10722797799826367, + "tests/baserow/contrib/database/view/test_view_filters.py::test_last_modified_date_equal_filter_type": 0.12883017000422115, + "tests/baserow/contrib/database/view/test_view_filters.py::test_last_modified_day_filter_type": 0.2059596950057312, + "tests/baserow/contrib/database/view/test_view_filters.py::test_last_modified_month_filter_type": 0.1608664079940354, + "tests/baserow/contrib/database/view/test_view_filters.py::test_last_modified_year_filter_type": 0.15300500099692727, + "tests/baserow/contrib/database/view/test_view_filters.py::test_length_is_lower_than_filter_type": 0.10620522400131449, + "tests/baserow/contrib/database/view/test_view_filters.py::test_link_row_has_filter_type": 0.206618914999126, + "tests/baserow/contrib/database/view/test_view_filters.py::test_link_row_has_not_filter_type": 0.22501945000112755, + "tests/baserow/contrib/database/view/test_view_filters.py::test_link_row_preload_values": 0.18105953199847136, + "tests/baserow/contrib/database/view/test_view_filters.py::test_lower_than_filter_type": 0.10472267699879012, + "tests/baserow/contrib/database/view/test_view_filters.py::test_multiple_select_has_filter_type": 0.14634874900002615, + "tests/baserow/contrib/database/view/test_view_filters.py::test_multiple_select_has_filter_type_export_import": 0.003970462999859592, + "tests/baserow/contrib/database/view/test_view_filters.py::test_multiple_select_has_not_filter_type": 0.15416503000233206, + "tests/baserow/contrib/database/view/test_view_filters.py::test_not_empty_filter_type": 0.30021176199807087, + "tests/baserow/contrib/database/view/test_view_filters.py::test_not_equal_filter_type": 0.13237587500043446, + "tests/baserow/contrib/database/view/test_view_filters.py::test_single_select_equal_filter_type": 0.0846742340036144, + "tests/baserow/contrib/database/view/test_view_filters.py::test_single_select_equal_filter_type_export_import": 0.0039250379959412385, + "tests/baserow/contrib/database/view/test_view_filters.py::test_single_select_not_equal_filter_type": 0.08896216400171397, + "tests/baserow/contrib/database/view/test_view_handler.py::test_apply_filters": 0.10788073499861639, + "tests/baserow/contrib/database/view/test_view_handler.py::test_apply_sortings": 0.11461946000054013, + "tests/baserow/contrib/database/view/test_view_handler.py::test_create_filter": 0.14262885700372863, + "tests/baserow/contrib/database/view/test_view_handler.py::test_create_form_view": 0.19531868299964117, + "tests/baserow/contrib/database/view/test_view_handler.py::test_create_grid_view": 0.13857273399844416, + "tests/baserow/contrib/database/view/test_view_handler.py::test_create_sort": 0.17232833099842537, + "tests/baserow/contrib/database/view/test_view_handler.py::test_delete_filter": 0.1036397730022145, + "tests/baserow/contrib/database/view/test_view_handler.py::test_delete_form_view": 0.09064433600724442, + "tests/baserow/contrib/database/view/test_view_handler.py::test_delete_grid_view": 0.12280264199944213, + "tests/baserow/contrib/database/view/test_view_handler.py::test_delete_sort": 0.09816297799625318, + "tests/baserow/contrib/database/view/test_view_handler.py::test_delete_view": 0.13421997200202895, + "tests/baserow/contrib/database/view/test_view_handler.py::test_enable_form_view_file_field": 0.07605773999966914, + "tests/baserow/contrib/database/view/test_view_handler.py::test_field_type_changed": 0.16467625699806376, + "tests/baserow/contrib/database/view/test_view_handler.py::test_get_filter": 0.13425086999632185, + "tests/baserow/contrib/database/view/test_view_handler.py::test_get_public_view_by_slug": 0.13742334299968206, + "tests/baserow/contrib/database/view/test_view_handler.py::test_get_public_views_which_include_row": 0.11014196299947798, + "tests/baserow/contrib/database/view/test_view_handler.py::test_get_sort": 0.1465922879979189, + "tests/baserow/contrib/database/view/test_view_handler.py::test_get_view": 0.14284267000402906, + "tests/baserow/contrib/database/view/test_view_handler.py::test_order_views": 0.1408833470013633, + "tests/baserow/contrib/database/view/test_view_handler.py::test_public_view_row_checker_caches_when_only_unfiltered_fields_updated": 0.08762302800096222, + "tests/baserow/contrib/database/view/test_view_handler.py::test_public_view_row_checker_does_not_cache_when_any_filtered_fields_updated": 0.09490771100172424, + "tests/baserow/contrib/database/view/test_view_handler.py::test_public_view_row_checker_includes_public_views_with_no_filters_with_no_queries": 0.09638960500524263, + "tests/baserow/contrib/database/view/test_view_handler.py::test_public_view_row_checker_runs_expected_queries_on_init": 0.09439595900039421, + "tests/baserow/contrib/database/view/test_view_handler.py::test_public_view_row_checker_runs_expected_queries_when_checking_rows": 0.09254271499958122, + "tests/baserow/contrib/database/view/test_view_handler.py::test_rotate_view_slug": 0.13327188000039314, + "tests/baserow/contrib/database/view/test_view_handler.py::test_submit_form_view": 0.05547137499524979, + "tests/baserow/contrib/database/view/test_view_handler.py::test_trashed_fields_are_not_included_in_grid_view_field_options": 0.08752861100219889, + "tests/baserow/contrib/database/view/test_view_handler.py::test_update_field_options": 0.171099420003884, + "tests/baserow/contrib/database/view/test_view_handler.py::test_update_filter": 0.1496533800054749, + "tests/baserow/contrib/database/view/test_view_handler.py::test_update_form_view": 0.18754136500137975, + "tests/baserow/contrib/database/view/test_view_handler.py::test_update_grid_view": 0.1290181240037782, + "tests/baserow/contrib/database/view/test_view_handler.py::test_update_sort": 0.1787991029996192, + "tests/baserow/contrib/database/view/test_view_models.py::test_rotate_view_slug": 0.020555585997499293, + "tests/baserow/contrib/database/view/test_view_models.py::test_view_get_field_options": 0.05497197400109144, + "tests/baserow/contrib/database/view/test_view_types.py::test_convert_card_cover_image_field_deleted": 0.08921796600407106, + "tests/baserow/contrib/database/view/test_view_types.py::test_convert_card_cover_image_field_to_another": 0.1021778060021461, + "tests/baserow/contrib/database/view/test_view_types.py::test_import_export_form_view": 0.08287754699995276, + "tests/baserow/contrib/database/view/test_view_types.py::test_import_export_gallery_view": 0.08687492100216332, + "tests/baserow/contrib/database/view/test_view_types.py::test_import_export_grid_view": 0.03848212999946554, + "tests/baserow/contrib/database/view/test_view_types.py::test_newly_created_gallery_view": 0.0951085279994004, + "tests/baserow/contrib/database/webhooks/test_webhook_handler.py::test_clean_webhook_calls": 0.02669710999907693, + "tests/baserow/contrib/database/webhooks/test_webhook_handler.py::test_create_webhook": 0.657179163001274, + "tests/baserow/contrib/database/webhooks/test_webhook_handler.py::test_delete_webhook": 0.12621436600238667, + "tests/baserow/contrib/database/webhooks/test_webhook_handler.py::test_find_webhooks_to_call": 0.04044353700373904, + "tests/baserow/contrib/database/webhooks/test_webhook_handler.py::test_get_all_table_webhooks": 0.1380431370016595, + "tests/baserow/contrib/database/webhooks/test_webhook_handler.py::test_get_webhook": 0.12239641899941489, + "tests/baserow/contrib/database/webhooks/test_webhook_handler.py::test_trigger_test_call": 0.1278186689960421, + "tests/baserow/contrib/database/webhooks/test_webhook_handler.py::test_update_webhook": 0.6982647259974328, + "tests/baserow/contrib/database/webhooks/test_webhook_models.py::test_header_validation": 0.5372012249972613, + "tests/baserow/contrib/database/webhooks/test_webhook_registries.py::test_signal_listener": 0.5854930930036062, + "tests/baserow/contrib/database/webhooks/test_webhook_tasks.py::test_call_webhook": 0.6144145339967508, + "tests/baserow/contrib/database/ws/public/test_public_ws_fields_signals.py::test_when_field_created_public_views_are_sent_field_created_with_restricted_related": 0.6984492399969895, + "tests/baserow/contrib/database/ws/public/test_public_ws_fields_signals.py::test_when_field_deleted_public_views_are_field_deleted_with_restricted_related": 0.6820015349985624, + "tests/baserow/contrib/database/ws/public/test_public_ws_fields_signals.py::test_when_field_restored_public_views_sent_event_with_restricted_related_fields": 0.7191184389994305, + "tests/baserow/contrib/database/ws/public/test_public_ws_fields_signals.py::test_when_field_updated_public_views_are_sent_event_with_restricted_related": 0.7352352119996794, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_given_row_invisible_in_public_view_when_moved_no_update_sent": 0.6547399340015545, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_given_row_not_visible_in_public_view_when_updated_to_be_visible_event_sent": 0.6668575709991273, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_given_row_visible_in_public_view_when_moved_row_updated_sent": 0.5904162459955842, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_given_row_visible_in_public_view_when_updated_to_be_not_visible_event_sent": 0.6374463799984369, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_given_row_visible_in_public_view_when_updated_to_still_be_visible_event_sent": 0.6773236419976456, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_when_row_created_public_views_receive_restricted_row_created_ws_event": 0.5929559100040933, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_when_row_created_public_views_receive_row_created_only_when_filters_match": 0.6889783089973207, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_when_row_deleted_public_views_receive_restricted_row_deleted_ws_event": 0.6233556069964834, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_when_row_deleted_public_views_receive_row_deleted_only_when_filters_match": 0.6621182020026026, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_when_row_restored_public_views_receive_restricted_row_created_ws_event": 0.6161719039992022, + "tests/baserow/contrib/database/ws/public/test_public_ws_rows_signals.py::test_when_row_restored_public_views_receive_row_created_only_when_filters_match": 0.7080331929973909, + "tests/baserow/contrib/database/ws/public/test_public_ws_view_signals.py::test_when_field_hidden_in_public_view_field_force_refresh_sent": 0.5828077940022922, + "tests/baserow/contrib/database/ws/public/test_public_ws_view_signals.py::test_when_field_unhidden_in_public_view_force_refresh_sent": 0.6459413560005487, + "tests/baserow/contrib/database/ws/public/test_public_ws_view_signals.py::test_when_only_field_options_updated_in_public_grid_view_force_refresh_sent": 0.6040824100018654, + "tests/baserow/contrib/database/ws/public/test_public_ws_view_signals.py::test_when_view_filter_created_for_public_view_force_refresh_sent": 0.5983676199975889, + "tests/baserow/contrib/database/ws/public/test_public_ws_view_signals.py::test_when_view_filter_deleted_for_public_view_force_refresh_event_sent": 0.646215270000539, + "tests/baserow/contrib/database/ws/public/test_public_ws_view_signals.py::test_when_view_filter_updated_for_public_view_force_refresh_event_sent": 0.6044446720006817, + "tests/baserow/contrib/database/ws/test_ws_fields_signals.py::test_field_created": 0.5536125540020294, + "tests/baserow/contrib/database/ws/test_ws_fields_signals.py::test_field_deleted": 0.6439217840015772, + "tests/baserow/contrib/database/ws/test_ws_fields_signals.py::test_field_restored": 0.6830584630042722, + "tests/baserow/contrib/database/ws/test_ws_fields_signals.py::test_field_restored_doesnt_do_n_plus_some_queries": 0.9676993550019688, + "tests/baserow/contrib/database/ws/test_ws_fields_signals.py::test_field_updated": 0.603592823001236, + "tests/baserow/contrib/database/ws/test_ws_rows_signals.py::test_populates_with_row_id_metadata": 0.0008048630006669555, + "tests/baserow/contrib/database/ws/test_ws_rows_signals.py::test_row_created": 0.5925468830027967, + "tests/baserow/contrib/database/ws/test_ws_rows_signals.py::test_row_created_with_metadata": 0.644433545996435, + "tests/baserow/contrib/database/ws/test_ws_rows_signals.py::test_row_deleted": 0.6248354689996631, + "tests/baserow/contrib/database/ws/test_ws_rows_signals.py::test_row_updated": 0.5936943989981955, + "tests/baserow/contrib/database/ws/test_ws_rows_signals.py::test_row_updated_with_metadata": 0.628945954998926, + "tests/baserow/contrib/database/ws/test_ws_table_signals.py::test_table_created": 0.5707974309989368, + "tests/baserow/contrib/database/ws/test_ws_table_signals.py::test_table_deleted": 0.6099812510001357, + "tests/baserow/contrib/database/ws/test_ws_table_signals.py::test_table_updated": 0.6306453399993188, + "tests/baserow/contrib/database/ws/test_ws_table_signals.py::test_tables_reordered": 0.5430184890028613, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_created": 0.6102939270022034, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_deleted": 0.6588476860051742, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_field_options_updated": 0.590165915000398, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_filter_created": 0.6346027579966176, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_filter_deleted": 0.5932950750029704, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_filter_updated": 0.5990396960005455, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_sort_created": 0.6455343229972641, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_sort_deleted": 0.6418277150005451, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_sort_updated": 0.5508354509984201, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_view_updated": 0.5854573760007042, + "tests/baserow/contrib/database/ws/test_ws_view_signals.py::test_views_reordered": 0.5566093139968871, + "tests/baserow/core/management/test_backup_runner.py::test_backup_baserow_does_no_table_batches_when_no_user_tables_found": 0.026912584002275253, + "tests/baserow/core/management/test_backup_runner.py::test_backup_baserow_dumps_database_in_batches": 0.11053236099905916, + "tests/baserow/core/management/test_backup_runner.py::test_backup_baserow_includes_all_tables_when_batch_size_matches_num_tables": 0.0258023360001971, + "tests/baserow/core/management/test_backup_runner.py::test_backup_baserow_table_batches_includes_all_tables_when_final_batch_small": 0.025930197996785864, + "tests/baserow/core/management/test_backup_runner.py::test_can_backup_and_restore_baserow_reverting_changes": 15.969413112001348, + "tests/baserow/core/management/test_backup_runner.py::test_can_change_num_jobs_and_insert_extra_args_for_baserow_backup": 0.02541104100237135, + "tests/baserow/core/management/test_backup_runner.py::test_restore_baserow_only_does_first_restore_if_no_user_tables": 0.010179372995480662, + "tests/baserow/core/management/test_backup_runner.py::test_restore_baserow_passes_extra_args_to_all_pg_restores_and_can_set_jobs": 0.013506477003829787, + "tests/baserow/core/management/test_backup_runner.py::test_restore_baserow_raises_exception_if_sub_folder_not_found_after_extract": 0.010046233994216891, + "tests/baserow/core/management/test_backup_runner.py::test_restore_baserow_restores_contained_dumps_in_batches": 0.010871413000131724, + "tests/baserow/core/migrations/test_fix_trash_constraint.py::test_migration_doesnt_fail_if_duplicate_entries_present_with_parent_id": 1.1343691219954053, + "tests/baserow/core/migrations/test_fix_trash_constraint.py::test_migration_doesnt_fail_if_duplicate_entries_present_without_parent_id": 1.3474722999999358, + "tests/baserow/core/test_core_applications.py::test_application_get_api_urls": 0.0007785529960528947, + "tests/baserow/core/test_core_applications.py::test_application_registry_get": 0.0008205009980883915, + "tests/baserow/core/test_core_applications.py::test_application_registry_register": 0.0008148909982992336, + "tests/baserow/core/test_core_db.py::test_locked_atomic_transaction": 0.0044997980003245175, + "tests/baserow/core/test_core_emails.py::test_base_email_message": 0.009651500000472879, + "tests/baserow/core/test_core_handler.py::test_accept_group_invitation": 0.26923468700260855, + "tests/baserow/core/test_core_handler.py::test_create_database_application": 0.12208251699848915, + "tests/baserow/core/test_core_handler.py::test_create_group": 0.06290209300277638, + "tests/baserow/core/test_core_handler.py::test_create_group_invitation": 0.17493936900064, + "tests/baserow/core/test_core_handler.py::test_delete_database_application": 0.12432106699998258, + "tests/baserow/core/test_core_handler.py::test_delete_group": 0.1314402189964312, + "tests/baserow/core/test_core_handler.py::test_delete_group_invitation": 0.11103900000307476, + "tests/baserow/core/test_core_handler.py::test_delete_group_user": 0.1636536639998667, + "tests/baserow/core/test_core_handler.py::test_export_import_group_application": 0.029664207002497278, + "tests/baserow/core/test_core_handler.py::test_get_application": 0.11117617799754953, + "tests/baserow/core/test_core_handler.py::test_get_group": 0.10985382199942251, + "tests/baserow/core/test_core_handler.py::test_get_group_invitation": 0.21192762300051982, + "tests/baserow/core/test_core_handler.py::test_get_group_invitation_by_token": 0.11346787599904928, + "tests/baserow/core/test_core_handler.py::test_get_group_user": 0.11610425300386851, + "tests/baserow/core/test_core_handler.py::test_get_settings": 0.004139058997679967, + "tests/baserow/core/test_core_handler.py::test_get_template": 0.06087272600416327, + "tests/baserow/core/test_core_handler.py::test_install_template": 0.3849930400028825, + "tests/baserow/core/test_core_handler.py::test_leave_group": 0.22125879099985468, + "tests/baserow/core/test_core_handler.py::test_order_applications": 0.12732515100287856, + "tests/baserow/core/test_core_handler.py::test_order_groups": 0.07089557599829277, + "tests/baserow/core/test_core_handler.py::test_reject_group_invitation": 0.16486689699740964, + "tests/baserow/core/test_core_handler.py::test_restore_application": 0.0667716130046756, + "tests/baserow/core/test_core_handler.py::test_restore_group": 0.06962363599814125, + "tests/baserow/core/test_core_handler.py::test_send_group_invitation_email": 0.5898950240007252, + "tests/baserow/core/test_core_handler.py::test_send_group_invitation_email_in_different_language": 0.6119825779969688, + "tests/baserow/core/test_core_handler.py::test_sync_and_install_all_templates": 58.52753264500279, + "tests/baserow/core/test_core_handler.py::test_sync_templates": 0.32755387899669586, + "tests/baserow/core/test_core_handler.py::test_update_database_application": 0.11374096999861649, + "tests/baserow/core/test_core_handler.py::test_update_group": 0.11242015699463082, + "tests/baserow/core/test_core_handler.py::test_update_group_invitation": 0.11909680599637795, + "tests/baserow/core/test_core_handler.py::test_update_group_user": 0.1623596940007701, + "tests/baserow/core/test_core_handler.py::test_update_settings": 0.11464017899925238, + "tests/baserow/core/test_core_mixins.py::test_cant_define_model_with_multiple_parents_with_poly_mixin": 0.006630734002101235, + "tests/baserow/core/test_core_mixins.py::test_get_all_parents_and_self_with_one_level_of_inheritance": 0.008566881995648146, + "tests/baserow/core/test_core_mixins.py::test_get_all_parents_and_self_with_single_model": 0.006856656000309158, + "tests/baserow/core/test_core_mixins.py::test_get_all_parents_and_self_with_two_levels_of_inheritance": 0.009020644996780902, + "tests/baserow/core/test_core_models.py::test_application_content_type_init": 0.009985417997086188, + "tests/baserow/core/test_core_models.py::test_created_and_updated_on_mixin": 0.03647177199673024, + "tests/baserow/core/test_core_models.py::test_group_has_user": 0.22278663999532, + "tests/baserow/core/test_core_models.py::test_group_user_get_next_order": 0.16515225800321787, + "tests/baserow/core/test_core_registry.py::test_api_exceptions_api_mixins": 0.0012554089989862405, + "tests/baserow/core/test_core_registry.py::test_get_serializer": 0.008793659999355441, + "tests/baserow/core/test_core_registry.py::test_registry": 0.0008723200007807463, + "tests/baserow/core/test_core_registry.py::test_registry_get": 0.000930599999264814, + "tests/baserow/core/test_core_registry.py::test_registry_get_by_model_returns_the_most_specific_value": 0.0011881730024470016, + "tests/baserow/core/test_core_registry.py::test_registry_register": 0.0008451280009467155, + "tests/baserow/core/test_core_utils.py::test_dict_to_object": 0.0008740329976717476, + "tests/baserow/core/test_core_utils.py::test_extract_allowed": 0.0008481440017931163, + "tests/baserow/core/test_core_utils.py::test_random_string": 0.0020111810008529574, + "tests/baserow/core/test_core_utils.py::test_remove_special_characters": 0.0008807549966149963, + "tests/baserow/core/test_core_utils.py::test_set_allowed_attrs": 0.0007922499971755315, + "tests/baserow/core/test_core_utils.py::test_sha256_hash": 0.0007909760024631396, + "tests/baserow/core/test_core_utils.py::test_split_comma_separated_string": 0.0007767889983369969, + "tests/baserow/core/test_core_utils.py::test_stream_size": 0.0007655289955437183, + "tests/baserow/core/test_core_utils.py::test_to_pascal_case": 0.0007740940018265974, + "tests/baserow/core/test_core_utils.py::test_to_snake_case": 0.0007694369960518088, + "tests/baserow/core/test_core_utils.py::test_truncate_middle": 0.0007917080001789145, + "tests/baserow/core/test_core_validators.py::test_max_length_validator_help_text": 0.0007631539956491906, + "tests/baserow/core/test_core_validators.py::test_max_length_validator_validate": 0.0008273240018752404, + "tests/baserow/core/trash/test_trash_handler.py::test_a_group_marked_for_perm_deletion_no_longer_shows_up_in_trash_structure": 0.07342177399914362, + "tests/baserow/core/trash/test_trash_handler.py::test_a_group_marked_for_perm_deletion_raises_a_404_when_asked_for_trash_contents": 0.08054747500136727, + "tests/baserow/core/trash/test_trash_handler.py::test_a_trash_entry_marked_for_permanent_deletion_gets_deleted_by_task": 0.09964143599790987, + "tests/baserow/core/trash/test_trash_handler.py::test_a_trash_entry_older_than_setting_gets_marked_for_permanent_deletion": 0.09916717399755726, + "tests/baserow/core/trash/test_trash_handler.py::test_a_trashed_app_shows_up_in_trash_structure": 0.08422898700155201, + "tests/baserow/core/trash/test_trash_handler.py::test_an_app_marked_for_perm_deletion_no_longer_shows_up_in_trash_structure": 0.0859317869944789, + "tests/baserow/core/trash/test_trash_handler.py::test_an_app_marked_for_perm_deletion_raises_a_404_when_asked_for_trash_contents": 0.07857910800157697, + "tests/baserow/core/trash/test_trash_handler.py::test_cannot_restore_a_child_before_the_parent": 0.1171903900030884, + "tests/baserow/core/trash/test_trash_handler.py::test_cant_trash_same_item_twice": 0.06745011900056852, + "tests/baserow/core/trash/test_trash_handler.py::test_cant_trash_same_row_twice": 0.08567831100299372, + "tests/baserow/core/trash/test_trash_handler.py::test_deleting_a_user_who_trashed_items_should_still_leave_those_items_trashed": 0.08632056799979182, + "tests/baserow/core/trash/test_trash_handler.py::test_perm_deleting_a_parent_with_a_trashed_child_also_cleans_up_the_child_entry": 0.1491440989993862, + "tests/baserow/core/trash/test_trash_handler.py::test_perm_deleting_a_table_with_a_trashed_row_also_cleans_up_the_row_entry": 0.15335945499828085, + "tests/baserow/core/trash/test_trash_handler.py::test_perm_deleting_one_group_should_not_effect_another_trashed_group": 0.08494473100290634, + "tests/baserow/core/trash/test_trash_handler.py::test_restoring_a_trashed_item_unmarks_it_as_trashed_and_deletes_the_entry": 0.06291215999954147, + "tests/baserow/core/trash/test_trash_handler.py::test_trash_contents_are_ordered_from_newest_to_oldest_entries": 0.10014789699926041, + "tests/baserow/core/trash/test_trash_handler.py::test_trashing_an_item_creates_a_trash_entry_in_the_db_and_marks_it_as_trashed": 0.0772075379936723, + "tests/baserow/core/trash/test_trash_handler.py::test_trashing_two_rows_in_different_tables_works_as_expected": 0.1333387330014375, + "tests/baserow/core/trash/test_trash_types.py::test_perm_delete_application": 0.08250658999895677, + "tests/baserow/core/trash/test_trash_types.py::test_perm_delete_group": 0.14601884600051562, + "tests/baserow/core/user/test_user_handler.py::test_change_password": 0.30597370699979365, + "tests/baserow/core/user/test_user_handler.py::test_change_password_invalid_new_password[984kds]": 0.15931809500034433, + "tests/baserow/core/user/test_user_handler.py::test_change_password_invalid_new_password[Bgvmt95en6HGJZ9Xz0F8xysQ6eYgo2Y54YzRPxxv10b5n16F4rZ6YH4ulonocwiFK6970KiAxoYhULYA3JFDPIQGj5gMZZl25M46sO810Zd3nyBg699a2TDMJdHG7hAAi0YeDnuHuabyBawnb4962OQ1OOf1MxzFyNWG7NR2X6MZQL5G1V61x56lQTXbvK1AG1IPM87bQ3YAtIBtGT2vK3Wd83q3he5ezMtUfzK2ibj0WWhf86DyQB4EHRUJjYcBiI78iEJv5hcu33X2I345YosO66cTBWK45SqJEDudrCOq]": 0.16538515700085554, + "tests/baserow/core/user/test_user_handler.py::test_change_password_invalid_new_password[]": 0.17130859999815584, + "tests/baserow/core/user/test_user_handler.py::test_change_password_invalid_new_password[a]": 0.16327080100381863, + "tests/baserow/core/user/test_user_handler.py::test_change_password_invalid_new_password[ab]": 0.16011766500014346, + "tests/baserow/core/user/test_user_handler.py::test_change_password_invalid_new_password[ask]": 0.15353751099974033, + "tests/baserow/core/user/test_user_handler.py::test_change_password_invalid_new_password[dsfkjh4]": 0.16148864400020102, + "tests/baserow/core/user/test_user_handler.py::test_change_password_invalid_new_password[dsj43]": 0.165707490996283, + "tests/baserow/core/user/test_user_handler.py::test_change_password_invalid_new_password[oiue]": 0.15400979499827372, + "tests/baserow/core/user/test_user_handler.py::test_create_user": 0.3695227909993264, + "tests/baserow/core/user/test_user_handler.py::test_create_user_invalid_password[984kds]": 0.005099795002024621, + "tests/baserow/core/user/test_user_handler.py::test_create_user_invalid_password[Bgvmt95en6HGJZ9Xz0F8xysQ6eYgo2Y54YzRPxxv10b5n16F4rZ6YH4ulonocwiFK6970KiAxoYhULYA3JFDPIQGj5gMZZl25M46sO810Zd3nyBg699a2TDMJdHG7hAAi0YeDnuHuabyBawnb4962OQ1OOf1MxzFyNWG7NR2X6MZQL5G1V61x56lQTXbvK1AG1IPM87bQ3YAtIBtGT2vK3Wd83q3he5ezMtUfzK2ibj0WWhf86DyQB4EHRUJjYcBiI78iEJv5hcu33X2I345YosO66cTBWK45SqJEDudrCOq]": 0.0064423190015077125, + "tests/baserow/core/user/test_user_handler.py::test_create_user_invalid_password[]": 0.009890920995530905, + "tests/baserow/core/user/test_user_handler.py::test_create_user_invalid_password[a]": 0.007471804001397686, + "tests/baserow/core/user/test_user_handler.py::test_create_user_invalid_password[ab]": 0.005542679002246587, + "tests/baserow/core/user/test_user_handler.py::test_create_user_invalid_password[ask]": 0.006674274998658802, + "tests/baserow/core/user/test_user_handler.py::test_create_user_invalid_password[dsfkjh4]": 0.004871738005022053, + "tests/baserow/core/user/test_user_handler.py::test_create_user_invalid_password[dsj43]": 0.004943190997437341, + "tests/baserow/core/user/test_user_handler.py::test_create_user_invalid_password[oiue]": 0.005029031995945843, + "tests/baserow/core/user/test_user_handler.py::test_create_user_with_invitation": 0.129768922997755, + "tests/baserow/core/user/test_user_handler.py::test_create_user_with_template": 0.15071183699910762, + "tests/baserow/core/user/test_user_handler.py::test_first_ever_created_user_is_staff": 0.3643979799999215, + "tests/baserow/core/user/test_user_handler.py::test_get_user": 0.060511234998557484, + "tests/baserow/core/user/test_user_handler.py::test_reset_password": 0.22714536099738325, + "tests/baserow/core/user/test_user_handler.py::test_reset_password_invalid_new_password[984kds]": 0.053738406000775285, + "tests/baserow/core/user/test_user_handler.py::test_reset_password_invalid_new_password[Bgvmt95en6HGJZ9Xz0F8xysQ6eYgo2Y54YzRPxxv10b5n16F4rZ6YH4ulonocwiFK6970KiAxoYhULYA3JFDPIQGj5gMZZl25M46sO810Zd3nyBg699a2TDMJdHG7hAAi0YeDnuHuabyBawnb4962OQ1OOf1MxzFyNWG7NR2X6MZQL5G1V61x56lQTXbvK1AG1IPM87bQ3YAtIBtGT2vK3Wd83q3he5ezMtUfzK2ibj0WWhf86DyQB4EHRUJjYcBiI78iEJv5hcu33X2I345YosO66cTBWK45SqJEDudrCOq]": 0.054227115000685444, + "tests/baserow/core/user/test_user_handler.py::test_reset_password_invalid_new_password[]": 0.06267809900236898, + "tests/baserow/core/user/test_user_handler.py::test_reset_password_invalid_new_password[a]": 0.06220668499736348, + "tests/baserow/core/user/test_user_handler.py::test_reset_password_invalid_new_password[ab]": 0.05995601300310227, + "tests/baserow/core/user/test_user_handler.py::test_reset_password_invalid_new_password[ask]": 0.05594563500199001, + "tests/baserow/core/user/test_user_handler.py::test_reset_password_invalid_new_password[dsfkjh4]": 0.05438919000152964, + "tests/baserow/core/user/test_user_handler.py::test_reset_password_invalid_new_password[dsj43]": 0.05403116600064095, + "tests/baserow/core/user/test_user_handler.py::test_reset_password_invalid_new_password[oiue]": 0.053548771003988804, + "tests/baserow/core/user/test_user_handler.py::test_send_reset_password_email": 0.789474060995417, + "tests/baserow/core/user/test_user_handler.py::test_send_reset_password_email_in_different_language": 0.5705998240046029, + "tests/baserow/core/user/test_user_handler.py::test_update_user": 0.057621055995696224, + "tests/baserow/core/user/test_user_utils.py::test_normalize_email_address": 0.0008570210047764704, + "tests/baserow/core/user_file/test_user_file_handler.py::test_generate_unique": 0.0796520439980668, + "tests/baserow/core/user_file/test_user_file_handler.py::test_upload_user_file": 0.49836105599752045, + "tests/baserow/core/user_file/test_user_file_handler.py::test_upload_user_file_by_url": 0.07465597199916374, + "tests/baserow/core/user_file/test_user_file_handler.py::test_upload_user_file_by_url_within_private_network": 0.0566709480008285, + "tests/baserow/core/user_file/test_user_file_handler.py::test_user_file_path": 0.06277800799216493, + "tests/baserow/core/user_file/test_user_file_handler.py::test_user_file_thumbnail_path": 0.05770440000560484, + "tests/baserow/core/user_file/test_user_file_managers.py::test_user_file_name": 0.1611323640026967, + "tests/baserow/core/user_file/test_user_file_models.py::test_serialize_user_file": 0.004540232996077975, + "tests/baserow/core/user_file/test_user_file_models.py::test_user_file_deconstruct_name": 0.005688883000402711, + "tests/baserow/core/user_file/test_user_file_models.py::test_user_file_name": 0.004567424999549985, + "tests/baserow/performance/test_formula_performance.py::test_adding_a_formula_field_compared_to_normal_field_isnt_slow": 0.00026241299929097295, + "tests/baserow/performance/test_formula_performance.py::test_altering_very_nested_formula_field": 0.00025552000079187565, + "tests/baserow/performance/test_formula_performance.py::test_creating_very_nested_formula_field": 0.0002566330040281173, + "tests/baserow/performance/test_formula_performance.py::test_fanout": 0.00025046099835890345, + "tests/baserow/performance/test_formula_performance.py::test_fanout_one_off": 0.00025357699996675365, + "tests/baserow/performance/test_formula_performance.py::test_getting_data_from_a_very_nested_formula_field": 0.000262633002421353, + "tests/baserow/performance/test_formula_performance.py::test_getting_data_from_normal_table": 0.0002520930029277224, + "tests/baserow/performance/test_formula_performance.py::test_very_nested_formula_field_change": 0.0002024609966611024, + "tests/baserow/performance/test_public_sharing_performance.py::test_creating_many_rows_in_public_filtered_views": 0.0002650679962243885, + "tests/baserow/performance/test_public_sharing_performance.py::test_updating_many_rows_in_public_filtered_views": 0.00026566900123725645, + "tests/baserow/performance/test_trash_performance.py::test_deleting_many_of_rows_is_fast": 0.0001645600023039151, + "tests/baserow/ws/test_ws_auth.py::test_get_user": 4.366128376997949, + "tests/baserow/ws/test_ws_auth.py::test_token_auth_middleware": 0.5682379379977647, + "tests/baserow/ws/test_ws_pages.py::test_join_page": 0.6582801769982325, + "tests/baserow/ws/test_ws_pages.py::test_join_page_as_anonymous_user": 0.5738481730040803, + "tests/baserow/ws/test_ws_registries.py::test_broadcast": 0.0012520839991339017, + "tests/baserow/ws/test_ws_signals.py::test_application_created": 0.6160604870019597, + "tests/baserow/ws/test_ws_signals.py::test_application_deleted": 0.6069545940008538, + "tests/baserow/ws/test_ws_signals.py::test_application_updated": 0.5305949130015506, + "tests/baserow/ws/test_ws_signals.py::test_applications_reordered": 0.5600783979971311, + "tests/baserow/ws/test_ws_signals.py::test_group_created": 0.5511975169974903, + "tests/baserow/ws/test_ws_signals.py::test_group_deleted": 0.6141822999961732, + "tests/baserow/ws/test_ws_signals.py::test_group_restored": 0.750764825999795, + "tests/baserow/ws/test_ws_signals.py::test_group_updated": 0.52879944700544, + "tests/baserow/ws/test_ws_signals.py::test_group_user_deleted": 0.6194850059982855, + "tests/baserow/ws/test_ws_signals.py::test_group_user_updated": 0.6187444249990222, + "tests/baserow/ws/test_ws_tasks.py::test_broadcast_to_channel_group": 1.6304658590051986, + "tests/baserow/ws/test_ws_tasks.py::test_broadcast_to_group": 1.2785801499994704, + "tests/baserow/ws/test_ws_tasks.py::test_broadcast_to_users": 0.8749475379991054 +} \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile index 3a2a6de0a..26061326c 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.7-slim-buster +FROM python:3.7-slim-buster as base ARG UID ENV UID=${UID:-9999} @@ -19,6 +19,7 @@ RUN apt-get update && \ dos2unix \ tini \ postgresql-client \ + gettext \ && apt-get autoclean \ && apt-get clean \ && apt-get autoremove \ @@ -26,13 +27,27 @@ RUN apt-get update && \ USER $UID:$GID -COPY --chown=$UID:$GID ./backend/requirements/base.txt /baserow/requirements/ -# Disable the path warn as we set the correct path in the entrypoint when it is easy -# to know the users $HOME/.local/bin location. Changing path in the docker image does -# not work as we do not know where $HOME when using an ENV command. -RUN pip3 install --no-warn-script-location -r /baserow/requirements/base.txt +# In slim docker images, mime.types is removed and we need it for mimetypes guessing +COPY --chown=$UID:$GID ./backend/docker/mime.types /etc/ +# Install non-dev base dependencies into a virtual env. +COPY --chown=$UID:$GID ./backend/requirements/base.txt /baserow/requirements/ +RUN python3 -m venv /baserow/venv +RUN . /baserow/venv/bin/activate && pip3 install -r /baserow/requirements/base.txt + +# Build a dev_deps stage which also has the dev dependencies for use by the dev layer. +FROM base as dev_deps + +COPY ./backend/requirements/dev.txt /baserow/requirements/ +RUN . /baserow/venv/bin/activate && pip3 install -r /baserow/requirements/dev.txt + +# The core stage contains all of Baserows source code and sets up the entrypoint +FROM base as core + +# Copy over backend code. COPY --chown=$UID:$GID ./docs /baserow/docs +# TODO - This copy also re-copies the requirements above, meaning this will be re-run +# and not cached even though we already have separate layers above. COPY --chown=$UID:$GID ./backend /baserow/backend COPY --chown=$UID:$GID ./premium/backend /baserow/premium/backend @@ -42,10 +57,24 @@ WORKDIR /baserow/backend # the application rather than buffering it. ENV PYTHONUNBUFFERED 1 ENV PYTHONPATH $PYTHONPATH:/baserow/backend/src:/baserow/premium/backend/src -ENV DJANGO_SETTINGS_MODULE='baserow.config.settings.base' +ENTRYPOINT ["/usr/bin/tini", "--", "/bin/bash", "/baserow/backend/docker/docker-entrypoint.sh"] +EXPOSE 8000 RUN dos2unix /baserow/backend/docker/docker-entrypoint.sh && \ chmod a+x /baserow/backend/docker/docker-entrypoint.sh -ENTRYPOINT ["/usr/bin/tini", "--", "/bin/bash", "/baserow/backend/docker/docker-entrypoint.sh"] + +FROM core as dev + +# Override virtualenv with one containing dev dependencies. +COPY --chown=$UID:$GID --from=dev_deps /baserow/venv /baserow/venv + +# Override env variables and initial cmd to start up in dev mode. +ENV DJANGO_SETTINGS_MODULE='baserow.config.settings.dev' +CMD ["dev"] + +FROM core as local + +ENV DJANGO_SETTINGS_MODULE='baserow.config.settings.base' CMD ["local"] + diff --git a/backend/Makefile b/backend/Makefile index 0308b1eb6..1f4708679 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -16,5 +16,37 @@ format: test: pytest tests ../premium/backend/tests || exit; +test-regenerate-ci-durations: + pytest tests ../premium/backend/tests --store-durations || exit; + test-parallel: pytest tests ../premium/backend/tests -n 10 || exit; + +PYTEST_SPLITS:=1 +PYTEST_SPLIT_GROUP:=1 +ci-test-python: + mkdir reports/ -p; \ + cd ..; \ + COVERAGE_FILE=backend/reports/.coverage.$(PYTEST_SPLIT_GROUP) \ + coverage run \ + --rcfile=backend/.coveragerc \ + -m pytest \ + --durations-path=backend/.test_durations \ + --splits $(PYTEST_SPLITS) \ + --group $(PYTEST_SPLIT_GROUP) \ + --junitxml=backend/reports/report.xml \ + backend/tests \ + premium/backend/tests; + +generate-html-coverage-report: + mkdir html_coverage/ -p; \ + cd ..; \ + coverage run --rcfile=backend/.coveragerc -m pytest \ + backend/tests \ + premium/backend/tests; \ + coverage html -d html_coverage/; + +ci-check-startup-python: + timeout --preserve-status 10s \ + gunicorn --workers=1 -b 0.0.0.0:8002 \ + -k uvicorn.workers.UvicornWorker baserow.config.asgi:application; diff --git a/backend/docker/Dockerfile.dev b/backend/docker/Dockerfile.dev deleted file mode 100644 index 1c2677d47..000000000 --- a/backend/docker/Dockerfile.dev +++ /dev/null @@ -1,55 +0,0 @@ -FROM python:3.7-slim-buster - -# Default to 1000 as this is probably the running users UID. -ARG UID -ENV UID=${UID:-1000} -ARG GID -ENV GID=${GID:-1000} - -# We might be running as a user which already exists in this image. In that situation -# Everything is OK and we should just continue on. -RUN groupadd -g $GID baserow_docker_group || exit 0 -RUN useradd --shell /bin/bash -u $UID -g $GID -o -c "" -m baserow_docker_user || exit 0 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - curl \ - gnupg2 \ - libpq-dev \ - dos2unix \ - tini \ - postgresql-client \ - gettext \ - && apt-get autoclean \ - && apt-get clean \ - && apt-get autoremove \ - && rm -rf /var/lib/apt/lists/* - -USER $UID:$GID - -COPY --chown=$UID:$GID ./backend/requirements /baserow/requirements -# In slim docker images, mime.types is removed and we need it for mimetypes guessing -COPY --chown=$UID:$GID ./backend/docker/mime.types /etc/ -# Disable the path warn as we set the correct path in the entrypoint when it is easy -# to know the users $HOME/.local/bin location. Changing path in the docker image does -# not work as we do not know where $HOME when using an ENV command. -RUN pip3 install --no-warn-script-location -r /baserow/requirements/base.txt -r /baserow/requirements/dev.txt - -COPY --chown=$UID:$GID ./docs /baserow/docs -COPY --chown=$UID:$GID ./backend /baserow/backend -COPY --chown=$UID:$GID ./premium/backend /baserow/premium/backend - -WORKDIR /baserow/backend - -# Ensure that Python outputs everything that's printed inside -# the application rather than buffering it. -ENV PYTHONUNBUFFERED 1 -ENV PYTHONPATH $PYTHONPATH:/baserow/backend/src:/baserow/premium/backend/src -ENV DJANGO_SETTINGS_MODULE='baserow.config.settings.dev' - -RUN dos2unix /baserow/backend/docker/docker-entrypoint.sh && \ - chmod a+x /baserow/backend/docker/docker-entrypoint.sh - -ENTRYPOINT ["/usr/bin/tini", "--", "/bin/bash", "/baserow/backend/docker/docker-entrypoint.sh"] -CMD ["dev"] diff --git a/backend/docker/docker-entrypoint.sh b/backend/docker/docker-entrypoint.sh index 380ff8520..4a61b3f60 100644 --- a/backend/docker/docker-entrypoint.sh +++ b/backend/docker/docker-entrypoint.sh @@ -9,8 +9,7 @@ DATABASE_USER="${DATABASE_USER:-postgres}" DATABASE_HOST="${DATABASE_HOST:-db}" DATABASE_PORT="${DATABASE_PORT:-5432}" -# Ensure the installed python dependencies are on the path and available. -export PATH="$PATH:$HOME/.local/bin" +source "/baserow/venv/bin/activate" postgres_ready() { python << END @@ -43,18 +42,24 @@ done show_help() { # If you change this please update ./docs/reference/baserow-docker-api.md echo """ -Usage: docker run <imagename> COMMAND +Usage: docker run [-T] baserow_backend[_dev] COMMAND Commands -local : Start django using a prod ready gunicorn server -dev : Start a normal Django development server -bash : Start a bash shell -manage : Start manage.py -python : Run a python command -shell : Start a Django Python shell -celery : Run celery -celery-dev: Run a hot-reloading dev version of celery -lint: : Run the linting -help : Show this message +local : Start django using a prod ready gunicorn server +dev : Start a normal Django development server +exec : Exec a command directly +bash : Start a bash shell +manage : Start manage.py +setup : Runs all setup commands (migrate, update_formulas, sync_templates) +python : Run a python command +shell : Start a Django Python shell +celery : Run celery +celery-dev: : Run a hot-reloading dev version of celery +lint: : Run the linting (only available if using dev target) +lint-exit : Run the linting and exit (only available if using dev target) +test: : Run the tests (only available if using dev target) +ci-test: : Run the tests for ci including various reports (dev only) +ci-check-startup: Start up a single gunicorn and timeout after 10 seconds for ci (dev). +help : Show this message """ } @@ -87,6 +92,9 @@ case "$1" in run_setup_commands_if_configured exec gunicorn --workers=3 -b 0.0.0.0:"${PORT}" -k uvicorn.workers.UvicornWorker baserow.config.asgi:application ;; + exec) + exec "${@:2}" + ;; bash) exec /bin/bash "${@:2}" ;; @@ -96,14 +104,31 @@ case "$1" in python) exec python "${@:2}" ;; + setup) + echo "python /baserow/backend/src/baserow/manage.py migrate" + python /baserow/backend/src/baserow/manage.py migrate + echo "python /baserow/backend/src/baserow/manage.py update_formulas" + python /baserow/backend/src/baserow/manage.py update_formulas + echo "python /baserow/backend/src/baserow/manage.py sync_templates" + python /baserow/backend/src/baserow/manage.py sync_templates + ;; shell) exec python /baserow/backend/src/baserow/manage.py shell ;; - lint) + lint-shell) CMD="make lint-python" echo "$CMD" exec bash --init-file <(echo "history -s $CMD; $CMD") ;; + lint) + exec make lint-python + ;; + ci-test) + exec make ci-test-python PYTEST_SPLITS="${PYTEST_SPLITS:-1}" PYTEST_SPLIT_GROUP="${PYTEST_SPLIT_GROUP:-1}" + ;; + ci-check-startup) + exec make ci-check-startup-python + ;; celery) exec celery -A baserow "${@:2}" ;; @@ -123,7 +148,8 @@ case "$1" in exec bash --init-file <(echo "history -s $CMD; $CMD") ;; *) + echo "${@:2}" show_help exit 1 ;; -esac \ No newline at end of file +esac diff --git a/backend/requirements/dev.txt b/backend/requirements/dev.txt index 387e7ffac..ac9f44a86 100644 --- a/backend/requirements/dev.txt +++ b/backend/requirements/dev.txt @@ -18,3 +18,6 @@ django-silk==4.2.0 django-extensions==3.1.5 snoop==0.4.1 openapi-spec-validator==0.4.0 +pytest-html==3.1.1 +coverage==6.2 +pytest-split==0.6.0 diff --git a/changelog.md b/changelog.md index 8825d3c54..c55c6d7c8 100644 --- a/changelog.md +++ b/changelog.md @@ -28,6 +28,7 @@ * Fix Django's default index naming scheme causing index name collisions. * Workaround bug in Django's schema editor sometimes causing incorrect transaction rollbacks resulting in the connection to the database becoming unusable. +* Rework Baserow docker images so they can be built and tested by gitlab CI. ## Released (2022-01-13 1.8.2) diff --git a/dev.sh b/dev.sh index b8c694e9e..77d8a3adb 100755 --- a/dev.sh +++ b/dev.sh @@ -232,6 +232,10 @@ else echo "./dev.sh Using the already set value for the env variable SYNC_TEMPLATES_ON_STARTUP = $SYNC_TEMPLATES_ON_STARTUP" fi +# Enable buildkit for faster builds with better caching. +export COMPOSE_DOCKER_CLI_BUILD=1 +export DOCKER_BUILDKIT=1 + echo "./dev.sh running docker-compose commands: ------------------------------------------------ " @@ -274,5 +278,5 @@ if [ "$dont_attach" != true ] && [ "$up" = true ] ; then "/bin/bash /baserow/web-frontend/docker/docker-entrypoint.sh lint-fix" launch_tab_and_exec "backend lint" \ "backend" \ - "/bin/bash /baserow/backend/docker/docker-entrypoint.sh lint" + "/bin/bash /baserow/backend/docker/docker-entrypoint.sh lint-shell" fi diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 1d34d389c..3d1cdbff1 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,4 +1,4 @@ -version: "3" +version: "3.4" services: @@ -8,8 +8,7 @@ services: backend: build: - context: . - dockerfile: ./backend/docker/Dockerfile.dev + target: dev args: # We allow configuring the UID/GID here so you can run as the dev's actual user # reducing the chance the containers screw up the bind mounted folders. @@ -26,8 +25,7 @@ services: celery: image: baserow_backend_dev:latest build: - context: . - dockerfile: ./backend/docker/Dockerfile.dev + target: dev args: # We allow configuring the UID/GID here so you can run as the dev's actual user # reducing the chance the containers screw up the bind mounted folders. @@ -44,8 +42,7 @@ services: celery-export-worker: image: baserow_backend_dev:latest build: - context: . - dockerfile: ./backend/docker/Dockerfile.dev + target: dev args: # We allow configuring the UID/GID here so you can run as the dev's actual user # reducing the chance the containers screw up the bind mounted folders. @@ -62,8 +59,7 @@ services: celery-beat-worker: image: baserow_backend_dev:latest build: - context: . - dockerfile: ./backend/docker/Dockerfile.dev + target: dev args: # We allow configuring the UID/GID here so you can run as the dev's actual user # reducing the chance the containers screw up the bind mounted folders. @@ -79,8 +75,7 @@ services: web-frontend: build: - context: . - dockerfile: ./web-frontend/docker/Dockerfile.dev + target: dev args: # We allow configuring the UID/GID here so you can run as the dev's actual user # reducing the chance the containers screw up the bind mounted folders. diff --git a/docker-compose.yml b/docker-compose.yml index 44b1caca9..2bab33fae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: "3" +version: "3.4" services: db: @@ -63,6 +63,9 @@ services: celery: image: baserow_backend:latest + build: + dockerfile: ./backend/Dockerfile + context: . environment: - ADDITIONAL_APPS - EMAIL_SMTP @@ -73,9 +76,6 @@ services: - EMAIL_SMTP_PASSWORD - FROM_EMAIL - DISABLE_ANONYMOUS_PUBLIC_VIEW_WS_CONNECTIONS - build: - dockerfile: ./backend/Dockerfile - context: . command: celery worker -l INFO -Q celery depends_on: - backend diff --git a/docs/development/directory-structure.md b/docs/development/directory-structure.md index eb0548636..6779a48e4 100644 --- a/docs/development/directory-structure.md +++ b/docs/development/directory-structure.md @@ -23,10 +23,8 @@ This whole directory is also added to the backend container. source directory. This file is registered as a command via the `setup.py`. When someone adds Baserow as a dependency they can use the command `baserow migrate` which is the same as `python src/baserow/manage.py migrate`. -* `Dockerfile`: the dockerfile that is used to build the image of the - backend for running baserow on your local machine. -* `docker/Dockerfile.dev`: the dockerfile that is used to build the development image - of the backend. +* `Dockerfile`: Builds an image containing just the backend service, build with + `--target dev` to instead get a dev ready image. * `Makefile`: contains a few commands to install the dependencies, run the linter and run the tests. * `pytest.ini`: pytest configuration when running the tests. @@ -85,10 +83,8 @@ web frontend. This whole directory is also added to the web-frontend container. * `.eslintrc.js`: the configuration for the eslint linter. * `.prettierrc`: configuration for prettier. * `.stylelintrc`: configuration for stylelint which lints the scss code. -* `Dockerfile`: the dockerfile that is used to build the image of the - web-frontend for running baserow on your local machine. -* `docker/Dockerfile.dev`: the dockerfile that is used to build the development image - of the web-frontend. +* `Dockerfile`: Builds an image containing just the web-frontend service, build with + `--target dev` to instead get a dev ready image. * `intellij-idea.webpack.config.js` a webpack config file that can be used by Intellij iDEA. It adds the correct aliases for the editor. * `jest.config.js`: config file for running the tests with JEST. diff --git a/docs/reference/baserow-docker-api.md b/docs/reference/baserow-docker-api.md index bee43be81..e17f86158 100644 --- a/docs/reference/baserow-docker-api.md +++ b/docs/reference/baserow-docker-api.md @@ -12,9 +12,9 @@ Below are the files used by our docker setup and what they are responsible for: - `docker-compose.yml`: A compose file which starts Baserow in local mode with no development features enabled. -- `./backend/Dockerfile`: The backend's Dockerfile for local mode. See below for +- `./backend/Dockerfile`: The backend's Dockerfile. See below for supported command line arguments. Also used to run the celery worker. -- `./web-frontend/Dockerfile`: The web-frontend's Dockerfile for local mode. See below +- `./web-frontend/Dockerfile`: The web-frontend's Dockerfile. See below for supported command line arguments. - `./media/Dockerfile`: A simple nginx image used to serve uploaded user files only. @@ -22,34 +22,41 @@ Below are the files used by our docker setup and what they are responsible for: - `docker-compose.dev.yml`: A compose file which overrides parts of `docker-compose.yml` to enable development features, do not use this in production. -- `./backend/docker/Dockerfile.dev`: The backends's Dockerfile for dev mode. -- `./web-frontend/docker/Dockerfile.dev`: The web-frontend's Dockerfile for dev mode. +- `./backend/docker/Dockerfile`: Build with `--target dev` to get the dev version. +- `./web-frontend/docker/Dockerfile`: Build with `--target dev` to get the dev version. ### For Both Envs -- `./backend/docker/docker-entrypoint.sh`: The entrypoint script used for both of the - backend images. -- `./web-frontend/docker/docker-entrypoint.sh`: The entrypoint script used for both of - the web-frontend images. +- `./backend/docker/docker-entrypoint.sh`: The entrypoint script used by the backend + Dockerfile, provides a set of commonly used commands for working with baserow. +- `./web-frontend/docker/docker-entrypoint.sh`: The entrypoint script used by the + web-frontend Dockerfile, provides a set of commonly used commands for working + with Baserow. ## Backend Image CLI The `baserow_backend` and `baserow_backend_dev` images provide various commands used to change what process is started inside the container. -```bash -Usage: docker run <imagename> COMMAND +```txt +Usage: docker run [-T] baserow_backend[_dev] COMMAND Commands -local : Start django using a prod ready gunicorn server -dev : Start a normal Django development server -bash : Start a bash shell -manage : Start manage.py -python : Run a python command -shell : Start a Django Python shell -celery : Run celery -celery-dev: Run a hot-reloading dev version of celery -lint: : Run the linting -help : Show this message +local : Start django using a prod ready gunicorn server +dev : Start a normal Django development server +exec : Exec a command directly. +bash : Start a bash shell +manage : Start manage.py +setup : Runs all setup commands (migrate, update_formulas, sync_templates) +python : Run a python command +shell : Start a Django Python shell +celery : Run celery +celery-dev: : Run a hot-reloading dev version of celery +lint: : Run the linting (only available if using dev target) +lint-exit : Run the linting and exit (only available if using dev target) +test: : Run the tests (only available if using dev target) +ci-test: : Run the tests for ci including various reports (dev only) +ci-check-startup: Start up a single gunicorn and timeout after 10 seconds for ci (dev). +help : Show this message ``` You can run one of these as a one off command like so: @@ -66,13 +73,18 @@ $ ./dev.sh run backend COMMAND The `baserow_web-frontend` and `baserow_web-frontend_dev` images provide various commands used to change what process is started inside the container. -```bash -Usage: docker run <imagename> COMMAND +```txt +Usage: docker run [-T] baserow_web-frontend[_dev] COMMAND Commands dev : Start a normal nuxt development server local : Start a non-dev prod ready nuxt server -lint : Run the linting +lint : Run all the linting lint-fix : Run eslint fix +stylelint: Run stylelint +eslint : Run eslint +test : Run jest tests +ci-test : Run ci tests with reporting +exec : Exec a command directly. bash : Start a bash shell help : Show this message ``` diff --git a/web-frontend/Dockerfile b/web-frontend/Dockerfile index c2d486dc5..108680e08 100644 --- a/web-frontend/Dockerfile +++ b/web-frontend/Dockerfile @@ -1,4 +1,4 @@ -FROM node:12-buster +FROM node:12-buster as base ARG UID ENV UID=${UID:-9999} @@ -38,7 +38,6 @@ RUN yarn install COPY --chown=$UID:$GID ./web-frontend /baserow/web-frontend/ COPY --chown=$UID:$GID ./premium/web-frontend /baserow/premium/web-frontend/ -RUN yarn run build-local RUN dos2unix /baserow/web-frontend/docker/docker-entrypoint.sh && \ chmod a+x /baserow/web-frontend/docker/docker-entrypoint.sh @@ -46,5 +45,16 @@ RUN dos2unix /baserow/web-frontend/docker/docker-entrypoint.sh && \ # tini installed above protects us from zombie processes and ensures the default signal # handlers work, see https://github.com/krallin/tini. ENTRYPOINT ["/usr/bin/tini", "--", "/bin/bash", "/baserow/web-frontend/docker/docker-entrypoint.sh"] +EXPOSE 3000 + +FROM base as dev + +# We don't bother running build-local in dev mode as it pre-compiles nuxt which won't +# be used when running the nuxt dev server. +CMD ["dev"] + +FROM base as local + +RUN yarn run build-local CMD ["local"] diff --git a/web-frontend/Makefile b/web-frontend/Makefile index 63f03b38f..9631d53dd 100644 --- a/web-frontend/Makefile +++ b/web-frontend/Makefile @@ -12,9 +12,15 @@ lint: eslint stylelint lint-javascript: lint jest: - yarn run jest || exit; + npx jest || exit; test: jest +unit-test: + npx jest --selectProjects unit --selectProjects premium || exit; + +ci-test-javascript: + JEST_JUNIT_OUTPUT_DIR=../reports/ npx jest --ci --collectCoverage --coverageDirectory="./reports/coverage/" || exit; + unit-test-watch: - yarn run jest test/unit --watch || exit; + npx jest test/unit --watch || exit; diff --git a/web-frontend/docker/Dockerfile.dev b/web-frontend/docker/Dockerfile.dev deleted file mode 100644 index d32db3e0b..000000000 --- a/web-frontend/docker/Dockerfile.dev +++ /dev/null @@ -1,47 +0,0 @@ -FROM node:12-buster - -ARG UID -ENV UID=${UID:-1000} -ARG GID -ENV GID=${GID:-1000} - -# Perform all OS package installation and cleanup in one single command to reduce the -# size of the created layer. -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - curl \ - gnupg2 \ - dos2unix \ - tini \ - && apt-get autoclean \ - && apt-get clean \ - && apt-get autoremove \ - && rm -rf /var/lib/apt/lists/* - -# The node image already creates a non-root user to run as, update its ids so they -# match the provided UID and GID we wish to build and run this image with. -# If GID or UID already exist that's OK no need to stop the build. -RUN groupmod -g ${GID} node || exit 0 -RUN usermod -u ${UID} -g ${GID} node || exit 0 - -USER $UID:$GID - -# Create and install the dependencies in separate COPY commands -COPY --chown=$UID:$GID ./web-frontend/package.json ./web-frontend/yarn.lock /baserow/web-frontend/ - -WORKDIR /baserow/web-frontend - -RUN yarn install - -COPY --chown=$UID:$GID ./web-frontend /baserow/web-frontend/ -COPY --chown=$UID:$GID ./premium/web-frontend /baserow/premium/web-frontend/ - -RUN dos2unix /baserow/web-frontend/docker/docker-entrypoint.sh && \ - chmod a+x /baserow/web-frontend/docker/docker-entrypoint.sh - -# tini installed above protects us from zombie processes and ensures the default signal -# handlers work, see https://github.com/krallin/tini. -ENTRYPOINT ["/usr/bin/tini", "--", "/bin/bash", "/baserow/web-frontend/docker/docker-entrypoint.sh"] -CMD ["dev"] - diff --git a/web-frontend/docker/docker-entrypoint.sh b/web-frontend/docker/docker-entrypoint.sh index 701119d8a..05ca758da 100644 --- a/web-frontend/docker/docker-entrypoint.sh +++ b/web-frontend/docker/docker-entrypoint.sh @@ -6,13 +6,18 @@ set -euo pipefail show_help() { # If you change this please update ./docs/reference/baserow-docker-api.md echo """ -Usage: docker run <imagename> COMMAND +Usage: docker run [-T] baserow_web-frontend[_dev] COMMAND Commands dev : Start a normal nuxt development server local : Start a non-dev prod ready nuxt server -lint : Run the linting +lint : Run all the linting lint-fix : Run eslint fix +stylelint: Run stylelint +eslint : Run eslint +test : Run jest tests +ci-test : Run ci tests with reporting bash : Start a bash shell +exec : Exec a command directly help : Show this message """ } @@ -38,11 +43,27 @@ case "$1" in echo "$CMD" exec bash --init-file <(echo "history -s $CMD; $CMD") ;; + eslint) + exec make eslint + ;; + stylelint) + exec make eslint + ;; + test) + exec make jest + ;; + ci-test) + exec make ci-test-javascript + ;; + exec) + exec "${@:2}" + ;; bash) exec /bin/bash "${@:2}" ;; *) + echo "${@:2}" show_help exit 1 ;; -esac \ No newline at end of file +esac diff --git a/web-frontend/jest.config.js b/web-frontend/jest.config.js index e10a635af..a8af17e68 100644 --- a/web-frontend/jest.config.js +++ b/web-frontend/jest.config.js @@ -1,9 +1,11 @@ -// The main jest config file used to run all of our tests. +// Setting reporters on the command line does not work so enable via this env variable +// we have to set anyway when using the junit reporter in CI. +const junitReporterConfig = process.env.JEST_JUNIT_OUTPUT_DIR + ? { + reporters: ['default', '<rootDir>/web-frontend/node_modules/jest-junit'], + } + : {} module.exports = { - // The rootDir used by jest must be the root of the repository so the premium tests - // and frontend code are contained within jest's rootDir. This is because: - // - Jest cannot collect coverage for files outside of its rootDir - // - Jest struggles to run tests which are outside of its rootDir. rootDir: '..', roots: ['<rootDir>/web-frontend/', '<rootDir>/premium/web-frontend'], moduleDirectories: ['<rootDir>/web-frontend/node_modules/'], @@ -13,4 +15,18 @@ module.exports = { '<rootDir>/premium/web-frontend/test/unit', '<rootDir>/web-frontend/test/server', ], + coverageReporters: [ + 'text-summary', + ['cobertura', { projectRoot: '/baserow/' }], + ], + collectCoverageFrom: [ + '<rootDir>/premium/web-frontend/modules/**/*.{js,Vue,vue}', + '<rootDir>/web-frontend/modules/**/*.{js,Vue,vue}', + '!**/node_modules/**', + '!**/.nuxt/**', + '!**/reports/**', + '!**/test/**', + '!**/generated/**', + ], + ...junitReporterConfig, } diff --git a/web-frontend/package.json b/web-frontend/package.json index cb0523165..5cb1b6eb9 100644 --- a/web-frontend/package.json +++ b/web-frontend/package.json @@ -64,6 +64,7 @@ "eslint-plugin-vue": "^7.14.0", "flush-promises": "^1.0.2", "jest": "^26.6.3", + "jest-junit": "^13.0.0", "jest-serializer-vue": "^2.0.2", "jsdom": "^16.6.0", "jsdom-global": "^3.0.2", diff --git a/web-frontend/yarn.lock b/web-frontend/yarn.lock index ff8a3cd71..eaf2347e4 100644 --- a/web-frontend/yarn.lock +++ b/web-frontend/yarn.lock @@ -2423,6 +2423,11 @@ ansi-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -6925,6 +6930,16 @@ jest-jasmine2@^26.6.3: pretty-format "^26.6.2" throat "^5.0.0" +jest-junit@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-13.0.0.tgz#479be347457aad98ae8a5983a23d7c3ec526c9a3" + integrity sha512-JSHR+Dhb32FGJaiKkqsB7AR3OqWKtldLd6ZH2+FJ8D4tsweb8Id8zEVReU4+OlrRO1ZluqJLQEETm+Q6/KilBg== + dependencies: + mkdirp "^1.0.4" + strip-ansi "^6.0.1" + uuid "^8.3.2" + xml "^1.0.1" + jest-leak-detector@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" @@ -11117,6 +11132,13 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -12033,7 +12055,7 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.0: +uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -12534,6 +12556,11 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"