Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@ dist
venv*/
.coverage
tests/
testkit/
testkitbackend/
108 changes: 81 additions & 27 deletions testkit/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,48 +1,70 @@
FROM ubuntu:20.04
ARG TIME_WARP=""
FROM ubuntu:20.04 AS base

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y locales && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 \
&& rm -rf /var/lib/apt/lists/*
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENV LANG=en_US.UTF-8

# Using apt-get update alone in a RUN statement causes caching issues and subsequent apt-get install instructions fail.
RUN apt-get --quiet update && apt-get --quiet install -y \
software-properties-common \
bash \
python3 \
python3-pip \
git \
curl \
tar \
wget \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update && \
apt-get install -y \
software-properties-common \
bash \
python3 \
python3-pip \
git \
curl \
tar \
wget && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install Build Tools
RUN apt-get update && \
apt-get install -y --no-install-recommends \
make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev \
libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev \
libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \
make \
build-essential \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev\
libsqlite3-dev \
wget \
curl \
llvm \
libncurses5-dev \
xz-utils \
tk-dev\
libxml2-dev \
libxmlsec1-dev \
libffi-dev \
liblzma-dev\
ca-certificates && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install our own CAs on the image.
# Assumes Linux Debian based image.
COPY CAs/* /usr/local/share/ca-certificates/
# Store custom CAs somewhere where the backend can find them later.
COPY CustomCAs/* /usr/local/share/custom-ca-certificates/
RUN update-ca-certificates
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install pyenv
RUN git clone https://github.com/pyenv/pyenv.git .pyenv
ENV PYENV_ROOT=/.pyenv
ENV PATH="$PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH"
ENV PIP_NO_CACHE_DIR=1

# Setup python version
ENV PYTHON_VERSIONS="3.13 3.12 3.11 3.10"

FROM base AS base-py-arg
# Install all supported Python versions
ARG PYTHON_VERSIONS="3.13 3.12 3.11 3.10"


FROM base AS base-py-arg-single-python
# Only install Python 3.10 in time warp mode
ARG PYTHON_VERSIONS="3.10"


FROM base-py-arg${TIME_WARP:+"-single-python"} AS base-py-install

RUN for version in $PYTHON_VERSIONS; do \
pyenv install $version; \
Expand All @@ -56,3 +78,35 @@ RUN pyenv global $(pyenv versions --bare --skip-aliases | sort --version-sort --
RUN for version in $PYTHON_VERSIONS; do \
python$version -m pip install -U pip; \
done

ARG TIME_WARP
ENV DRIVER_TIME_WARP=$TIME_WARP


FROM base-py-install AS backend-timewarp
WORKDIR /home/root/testkit

COPY testkit/backend.py testkit/build.py testkit/_common.py testkit/
COPY pyproject.toml .

RUN for version in $PYTHON_VERSIONS; do \
TEST_BACKEND_VERSION="python$version" python testkit/build.py && \
python$version -m pip install --force-reinstall neo4j==${TIME_WARP}; \
done
COPY testkitbackend ./testkitbackend
ENTRYPOINT ["python", "testkit/backend.py"]


FROM base-py-install AS backend

# Install our own CAs on the image.
# Assumes Linux Debian based image.
COPY CAs/* /usr/local/share/ca-certificates/
# Store custom CAs somewhere where the backend can find them later.
COPY CustomCAs/* /usr/local/share/custom-ca-certificates/
RUN update-ca-certificates


FROM backend${TIME_WARP:+"-timewarp"} AS final
WORKDIR /home/root/testkit
EXPOSE 9876/tcp
1 change: 1 addition & 0 deletions testkit/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@


TEST_BACKEND_VERSION = os.getenv("TEST_BACKEND_VERSION", "python")
DRIVER_TIME_WARP = os.getenv("DRIVER_TIME_WARP")


def run(args, env=None):
Expand Down
3 changes: 2 additions & 1 deletion testkit/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@
cmd = ["-m", "testkitbackend"]
if "TEST_BACKEND_SERVER" in os.environ:
cmd.append(os.environ["TEST_BACKEND_SERVER"])
run_python(cmd)
is_time_warp = bool(os.environ.get("DRIVER_TIME_WARP"))
run_python(cmd, warning_as_error=not is_time_warp)
14 changes: 13 additions & 1 deletion testkit/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,22 @@

"""Building driver and test backend inside driver container."""

from _common import run_python
import sys

from _common import (
DRIVER_TIME_WARP,
run_python,
)


if __name__ == "__main__":
if DRIVER_TIME_WARP:
run_python(
["-m", "pip", "install", "-U", "--group", "testkit"],
warning_as_error=False,
)
sys.exit(0)

run_python(
["-m", "pip", "install", "-U", "pip"],
warning_as_error=False,
Expand Down
7 changes: 4 additions & 3 deletions testkitbackend/_async/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
)
from .._warning_check import warnings_check
from ..exceptions import MarkdAsDriverError
from ..test_config import (
FEATURES,
SKIPPED_TESTS,
)


if t.TYPE_CHECKING:
Expand Down Expand Up @@ -108,9 +112,6 @@ def load_config():
return skips, features


SKIPPED_TESTS, FEATURES = load_config()


def _get_skip_reason(test_name):
for skip_pattern, reason in SKIPPED_TESTS.items():
if skip_pattern[0] == skip_pattern[-1] == "'":
Expand Down
7 changes: 4 additions & 3 deletions testkitbackend/_sync/requests.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions testkitbackend/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,27 @@
# limitations under the License.


from .time_warp_compat import VERSION


class MarkdAsDriverError(Exception):
"""Wrap any error as DriverException."""

def __init__(self, wrapped_exc):
super().__init__()
self.wrapped_exc = wrapped_exc


class TimeWarpError(Exception):
"""
Request cannot be fulfilled with in the current time warp mode.

The backend understood the request, but is running in time warp mode
against an older driver that does not support the requested feature.
"""

def __init__(self, feature_name: str):
super().__init__(
f"{feature_name.capitalize()} is not supported in time warp mode "
f"(driver version {'.'.join(map(str, VERSION))})."
)
2 changes: 1 addition & 1 deletion testkitbackend/test_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"Feature:Bolt:5.2": true,
"Feature:Bolt:5.3": true,
"Feature:Bolt:5.4": true,
"Feature:Bolt:5.5": true,
"Feature:Bolt:5.5": "Version was never released in a server",
"Feature:Bolt:5.6": true,
"Feature:Bolt:5.7": true,
"Feature:Bolt:5.8": true,
Expand Down
46 changes: 46 additions & 0 deletions testkitbackend/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright (c) "Neo4j"
# Neo4j Sweden AB [https://neo4j.com]
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import json
import ssl
from os import path

from .time_warp_compat import (
BLOCKED_TESTKIT_FEATURES,
EXTRA_TESTKIT_FEATURES,
)


__all__ = ["FEATURES", "SKIPPED_TESTS"]


def _load_config():
config_path = path.join(path.dirname(__file__), "test_config.json")
with open(config_path, encoding="utf-8") as fd:
config = json.load(fd)
skips = config["skips"]
features = [
k
for k, v in config["features"].items()
if v is True and k not in BLOCKED_TESTKIT_FEATURES
]
features.extend(EXTRA_TESTKIT_FEATURES)
if ssl.HAS_TLSv1_3:
features += ["Feature:TLS:1.3"]
return skips, features


SKIPPED_TESTS, FEATURES = _load_config()
59 changes: 59 additions & 0 deletions testkitbackend/time_warp_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright (c) "Neo4j"
# Neo4j Sweden AB [https://neo4j.com]
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


from __future__ import annotations

import os
import typing as t


if t.TYPE_CHECKING:
import typing_extensions as te


__all__ = [
"BLOCKED_TESTKIT_FEATURES",
"EXTRA_TESTKIT_FEATURES",
"VERSION",
]


def _get_time_warp_version() -> tuple[float, ...]:
time_warp_env = os.environ.get("DRIVER_TIME_WARP")
if not time_warp_env:
return (float("inf"),)
return tuple(int(e) for e in time_warp_env.split("."))


VERSION: te.Final[tuple[float, ...]] = _get_time_warp_version()


def _get_blocked_testkit_features() -> frozenset[str]:
blocked: list[str] = []
return frozenset(blocked)


def _get_extra_testkit_features() -> frozenset[str]:
extra: list[str] = []
return frozenset(extra)


BLOCKED_TESTKIT_FEATURES: te.Final[frozenset[str]] = (
_get_blocked_testkit_features()
)
EXTRA_TESTKIT_FEATURES: te.Final[frozenset[str]] = (
_get_extra_testkit_features()
)