[CI] Automatic rerun of certain test failures (#36694)
This commit is contained in:
@@ -33,6 +33,26 @@ COMMON_ENV_VARIABLES = {
|
|||||||
COMMON_PYTEST_OPTIONS = {"max-worker-restart": 0, "dist": "loadfile", "vvv": None, "rsfE":None}
|
COMMON_PYTEST_OPTIONS = {"max-worker-restart": 0, "dist": "loadfile", "vvv": None, "rsfE":None}
|
||||||
DEFAULT_DOCKER_IMAGE = [{"image": "cimg/python:3.8.12"}]
|
DEFAULT_DOCKER_IMAGE = [{"image": "cimg/python:3.8.12"}]
|
||||||
|
|
||||||
|
# Strings that commonly appear in the output of flaky tests when they fail. These are used with `pytest-rerunfailures`
|
||||||
|
# to rerun the tests that match these patterns.
|
||||||
|
FLAKY_TEST_FAILURE_PATTERNS = [
|
||||||
|
"OSError", # Machine/connection transient error
|
||||||
|
"Timeout", # Machine/connection transient error
|
||||||
|
"ConnectionError", # Connection transient error
|
||||||
|
"FileNotFoundError", # Raised by `datasets` on Hub failures
|
||||||
|
"PIL.UnidentifiedImageError", # Raised by `PIL.Image.open` on connection issues
|
||||||
|
"HTTPError.*502", # Hub-related
|
||||||
|
"HTTPError.*504", # Hub-related
|
||||||
|
"AssertionError: Tensor-likes are not close!", # `torch.testing.assert_close`, we might have unlucky random values
|
||||||
|
# TODO: error downloading tokenizer's `merged.txt` from hub can cause all the exceptions below. Throw and handle
|
||||||
|
# them under a single message.
|
||||||
|
"TypeError: expected str, bytes or os.PathLike object, not NoneType",
|
||||||
|
"TypeError: stat: path should be string, bytes, os.PathLike or integer, not NoneType",
|
||||||
|
"Converting from Tiktoken failed",
|
||||||
|
"KeyError: <class ",
|
||||||
|
"TypeError: not a string",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class EmptyJob:
|
class EmptyJob:
|
||||||
job_name = "empty"
|
job_name = "empty"
|
||||||
@@ -124,7 +144,9 @@ class CircleCIJob:
|
|||||||
# Examples special case: we need to download NLTK files in advance to avoid cuncurrency issues
|
# Examples special case: we need to download NLTK files in advance to avoid cuncurrency issues
|
||||||
timeout_cmd = f"timeout {self.command_timeout} " if self.command_timeout else ""
|
timeout_cmd = f"timeout {self.command_timeout} " if self.command_timeout else ""
|
||||||
marker_cmd = f"-m '{self.marker}'" if self.marker is not None else ""
|
marker_cmd = f"-m '{self.marker}'" if self.marker is not None else ""
|
||||||
additional_flags = f" -p no:warning -o junit_family=xunit1 --junitxml=test-results/junit.xml"
|
junit_flags = f" -p no:warning -o junit_family=xunit1 --junitxml=test-results/junit.xml"
|
||||||
|
joined_flaky_patterns = "|".join(FLAKY_TEST_FAILURE_PATTERNS)
|
||||||
|
repeat_on_failure_flags = f"--reruns 5 --reruns-delay 2 --only-rerun '({joined_flaky_patterns})'"
|
||||||
parallel = f' << pipeline.parameters.{self.job_name}_parallelism >> '
|
parallel = f' << pipeline.parameters.{self.job_name}_parallelism >> '
|
||||||
steps = [
|
steps = [
|
||||||
"checkout",
|
"checkout",
|
||||||
@@ -152,7 +174,7 @@ class CircleCIJob:
|
|||||||
},
|
},
|
||||||
{"run": {
|
{"run": {
|
||||||
"name": "Run tests",
|
"name": "Run tests",
|
||||||
"command": f"({timeout_cmd} python3 -m pytest {marker_cmd} -n {self.pytest_num_workers} {additional_flags} {' '.join(pytest_flags)} $(cat splitted_tests.txt) | tee tests_output.txt)"}
|
"command": f"({timeout_cmd} python3 -m pytest {marker_cmd} -n {self.pytest_num_workers} {junit_flags} {repeat_on_failure_flags} {' '.join(pytest_flags)} $(cat splitted_tests.txt) | tee tests_output.txt)"}
|
||||||
},
|
},
|
||||||
{"run": {"name": "Expand to show skipped tests", "when": "always", "command": f"python3 .circleci/parse_test_outputs.py --file tests_output.txt --skip"}},
|
{"run": {"name": "Expand to show skipped tests", "when": "always", "command": f"python3 .circleci/parse_test_outputs.py --file tests_output.txt --skip"}},
|
||||||
{"run": {"name": "Failed tests: show reasons", "when": "always", "command": f"python3 .circleci/parse_test_outputs.py --file tests_output.txt --fail"}},
|
{"run": {"name": "Failed tests: show reasons", "when": "always", "command": f"python3 .circleci/parse_test_outputs.py --file tests_output.txt --fail"}},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
FROM python:3.9-slim
|
FROM python:3.9-slim
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
|
ARG REF=main
|
||||||
USER root
|
USER root
|
||||||
RUN apt-get update && apt-get install -y libsndfile1-dev espeak-ng time git cmake wget xz-utils build-essential g++5 libprotobuf-dev protobuf-compiler
|
RUN apt-get update && apt-get install -y libsndfile1-dev espeak-ng time git cmake wget xz-utils build-essential g++5 libprotobuf-dev protobuf-compiler
|
||||||
ENV UV_PYTHON=/usr/local/bin/python
|
ENV UV_PYTHON=/usr/local/bin/python
|
||||||
@@ -17,7 +18,7 @@ RUN make install -j 10
|
|||||||
|
|
||||||
RUN uv pip install --no-cache --upgrade 'torch' --index-url https://download.pytorch.org/whl/cpu
|
RUN uv pip install --no-cache --upgrade 'torch' --index-url https://download.pytorch.org/whl/cpu
|
||||||
RUN uv pip install --no-cache-dir --no-deps accelerate --extra-index-url https://download.pytorch.org/whl/cpu
|
RUN uv pip install --no-cache-dir --no-deps accelerate --extra-index-url https://download.pytorch.org/whl/cpu
|
||||||
RUN uv pip install --no-cache-dir "transformers[ja,testing,sentencepiece,jieba,spacy,ftfy,rjieba]" unidic unidic-lite
|
RUN uv pip install --no-cache-dir "git+https://github.com/huggingface/transformers.git@${REF}#egg=transformers[ja,testing,sentencepiece,jieba,spacy,ftfy,rjieba]" unidic unidic-lite
|
||||||
# spacy is not used so not tested. Causes to failures. TODO fix later
|
# spacy is not used so not tested. Causes to failures. TODO fix later
|
||||||
RUN python3 -m unidic download
|
RUN python3 -m unidic download
|
||||||
RUN pip uninstall -y transformers
|
RUN pip uninstall -y transformers
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
FROM python:3.9-slim
|
FROM python:3.9-slim
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
|
ARG REF=main
|
||||||
USER root
|
USER root
|
||||||
RUN apt-get update && apt-get install -y libsndfile1-dev espeak-ng time git
|
RUN apt-get update && apt-get install -y libsndfile1-dev espeak-ng time git
|
||||||
RUN apt-get install -y g++ cmake
|
RUN apt-get install -y g++ cmake
|
||||||
ENV UV_PYTHON=/usr/local/bin/python
|
ENV UV_PYTHON=/usr/local/bin/python
|
||||||
RUN pip --no-cache-dir install uv && uv venv
|
RUN pip --no-cache-dir install uv && uv venv
|
||||||
RUN uv pip install --no-cache-dir -U pip setuptools albumentations seqeval
|
RUN uv pip install --no-cache-dir -U pip setuptools albumentations seqeval
|
||||||
RUN pip install --upgrade --no-cache-dir "transformers[tf-cpu,sklearn,testing,sentencepiece,tf-speech,vision]"
|
RUN pip install --upgrade --no-cache-dir "git+https://github.com/huggingface/transformers.git@${REF}#egg=transformers[tf-cpu,sklearn,testing,sentencepiece,tf-speech,vision]"
|
||||||
RUN uv pip install --no-cache-dir "protobuf==3.20.3"
|
RUN uv pip install --no-cache-dir "protobuf==3.20.3"
|
||||||
RUN pip uninstall -y transformers
|
RUN pip uninstall -y transformers
|
||||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
FROM python:3.9-slim
|
FROM python:3.9-slim
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
|
ARG REF=main
|
||||||
USER root
|
USER root
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends libsndfile1-dev espeak-ng time git g++ cmake pkg-config openssh-client git
|
RUN apt-get update && apt-get install -y --no-install-recommends libsndfile1-dev espeak-ng time git g++ cmake pkg-config openssh-client git
|
||||||
ENV UV_PYTHON=/usr/local/bin/python
|
ENV UV_PYTHON=/usr/local/bin/python
|
||||||
RUN pip --no-cache-dir install uv && uv venv && uv pip install --no-cache-dir -U pip setuptools
|
RUN pip --no-cache-dir install uv && uv venv && uv pip install --no-cache-dir -U pip setuptools
|
||||||
RUN pip install --no-cache-dir 'torch' 'torchvision' 'torchaudio' --index-url https://download.pytorch.org/whl/cpu
|
RUN pip install --no-cache-dir 'torch' 'torchvision' 'torchaudio' --index-url https://download.pytorch.org/whl/cpu
|
||||||
RUN uv pip install --no-deps timm accelerate --extra-index-url https://download.pytorch.org/whl/cpu
|
RUN uv pip install --no-deps timm accelerate --extra-index-url https://download.pytorch.org/whl/cpu
|
||||||
RUN uv pip install --no-cache-dir librosa "transformers[sklearn,sentencepiece,vision,testing]" seqeval albumentations jiwer
|
RUN uv pip install --no-cache-dir librosa "git+https://github.com/huggingface/transformers.git@${REF}#egg=transformers[sklearn,sentencepiece,vision,testing]" seqeval albumentations jiwer
|
||||||
RUN pip uninstall -y transformers
|
RUN pip uninstall -y transformers
|
||||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
2
setup.py
2
setup.py
@@ -150,6 +150,7 @@ _deps = [
|
|||||||
"pydantic",
|
"pydantic",
|
||||||
"pytest>=7.2.0,<8.0.0",
|
"pytest>=7.2.0,<8.0.0",
|
||||||
"pytest-asyncio",
|
"pytest-asyncio",
|
||||||
|
"pytest-rerunfailures",
|
||||||
"pytest-timeout",
|
"pytest-timeout",
|
||||||
"pytest-xdist",
|
"pytest-xdist",
|
||||||
"pytest-order",
|
"pytest-order",
|
||||||
@@ -326,6 +327,7 @@ extras["testing"] = (
|
|||||||
"pytest-rich",
|
"pytest-rich",
|
||||||
"pytest-xdist",
|
"pytest-xdist",
|
||||||
"pytest-order",
|
"pytest-order",
|
||||||
|
"pytest-rerunfailures",
|
||||||
"timeout-decorator",
|
"timeout-decorator",
|
||||||
"parameterized",
|
"parameterized",
|
||||||
"psutil",
|
"psutil",
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ deps = {
|
|||||||
"pydantic": "pydantic",
|
"pydantic": "pydantic",
|
||||||
"pytest": "pytest>=7.2.0,<8.0.0",
|
"pytest": "pytest>=7.2.0,<8.0.0",
|
||||||
"pytest-asyncio": "pytest-asyncio",
|
"pytest-asyncio": "pytest-asyncio",
|
||||||
|
"pytest-rerunfailures": "pytest-rerunfailures",
|
||||||
"pytest-timeout": "pytest-timeout",
|
"pytest-timeout": "pytest-timeout",
|
||||||
"pytest-xdist": "pytest-xdist",
|
"pytest-xdist": "pytest-xdist",
|
||||||
"pytest-order": "pytest-order",
|
"pytest-order": "pytest-order",
|
||||||
|
|||||||
@@ -2518,6 +2518,11 @@ def is_flaky(max_attempts: int = 5, wait_before_retry: Optional[float] = None, d
|
|||||||
"""
|
"""
|
||||||
To decorate flaky tests. They will be retried on failures.
|
To decorate flaky tests. They will be retried on failures.
|
||||||
|
|
||||||
|
Please note that our push tests use `pytest-rerunfailures`, which prompts the CI to rerun certain types of
|
||||||
|
failed tests. More specifically, if the test exception contains any substring in `FLAKY_TEST_FAILURE_PATTERNS`
|
||||||
|
(in `.circleci/create_circleci_config.py`), it will be rerun. If you find a recurrent pattern of failures,
|
||||||
|
expand `FLAKY_TEST_FAILURE_PATTERNS` in our CI configuration instead of using `is_flaky`.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
max_attempts (`int`, *optional*, defaults to 5):
|
max_attempts (`int`, *optional*, defaults to 5):
|
||||||
The maximum number of attempts to retry the flaky test.
|
The maximum number of attempts to retry the flaky test.
|
||||||
|
|||||||
Reference in New Issue
Block a user