Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve CI test runtime with pytest-xdist #270

Merged
merged 11 commits into from
Feb 7, 2025
2 changes: 2 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ jobs:
# so linting on fewer versions makes CI faster.
python-version:
- "3.9"
- "3.10"
- "3.11"
- "3.12"

steps:
- uses: actions/checkout@v2
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.9, '3.10', 3.11]
python-version: [3.9, '3.10', 3.11, 3.12]
connection: ['hiredis', 'plain']
redis-stack-version: ['6.2.6-v9', 'latest', 'edge']

Expand Down Expand Up @@ -75,12 +75,12 @@ jobs:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
poetry run test-cov
poetry run test-verbose

- name: Run tests
if: matrix.connection != 'plain' || matrix.redis-stack-version != 'latest'
run: |
SKIP_VECTORIZERS=True SKIP_RERANKERS=True poetry run test-cov
SKIP_VECTORIZERS=True SKIP_RERANKERS=True poetry run test-verbose

- name: Run notebooks
if: matrix.connection == 'plain' && matrix.redis-stack-version == 'latest'
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,17 @@ To run Testcontainers-based tests you need a local Docker installation such as:

Tests w/ vectorizers:
```bash
poetry run test-cov
poetry run test-verbose
```

Tests w/out vectorizers:
```bash
SKIP_VECTORIZERS=true poetry run test-cov
SKIP_VECTORIZERS=true poetry run test-verbose
```

Tests w/out rerankers:
```bash
SKIP_RERANKERS=true poetry run test-cov
SKIP_RERANKERS=true poetry run test-verbose
```

### Documentation
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ check-types:
lint: format check-types

test:
SKIP_RERANKERS=true SKIP_VECTORIZERS=true poetry run test-cov
SKIP_RERANKERS=true SKIP_VECTORIZERS=true poetry run test-verbose

test-all:
poetry run test-cov
poetry run test-verbose

check: lint test

Expand Down
48 changes: 36 additions & 12 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,55 @@
import os
import pytest
import asyncio

from redisvl.redis.connection import RedisConnectionFactory
from testcontainers.compose import DockerCompose


@pytest.fixture(autouse=True)
def set_tokenizers_parallelism():
"""Disable tokenizers parallelism in tests to avoid deadlocks"""
os.environ["TOKENIZERS_PARALLELISM"] = "false"


@pytest.fixture(scope="session", autouse=True)
def redis_container():
# Set the default Redis version if not already set
def redis_container(request):
"""
Create a unique Compose project for each xdist worker by setting
COMPOSE_PROJECT_NAME. That prevents collisions on container/volume names.
"""
# In xdist, the config has "workerid" in workerinput
worker_id = request.config.workerinput.get("workerid", "master")

# Set the Compose project name so containers do not clash across workers
os.environ["COMPOSE_PROJECT_NAME"] = f"redis_test_{worker_id}"
os.environ.setdefault("REDIS_VERSION", "edge")

compose = DockerCompose("tests", compose_file_name="docker-compose.yml", pull=True)
compose = DockerCompose(
context="tests",
compose_file_name="docker-compose.yml",
pull=True,
)
compose.start()

redis_host, redis_port = compose.get_service_host_and_port("redis", 6379)
redis_url = f"redis://{redis_host}:{redis_port}"
os.environ["REDIS_URL"] = redis_url

yield compose

compose.stop()


@pytest.fixture(scope="session")
def redis_url():
return os.getenv("REDIS_URL", "redis://localhost:6379")
def redis_url(redis_container):
"""
Use the `DockerCompose` fixture to get host/port of the 'redis' service
on container port 6379 (mapped to an ephemeral port on the host).
"""
host, port = redis_container.get_service_host_and_port("redis", 6379)
return f"redis://{host}:{port}"

@pytest.fixture
async def async_client(redis_url):
"""
An async Redis client that uses the dynamic `redis_url`.
"""
client = await RedisConnectionFactory.get_async_redis_connection(redis_url)
yield client
try:
Expand All @@ -38,8 +59,11 @@ async def async_client(redis_url):
raise

@pytest.fixture
def client():
conn = RedisConnectionFactory.get_redis_connection(os.environ["REDIS_URL"])
def client(redis_url):
"""
A sync Redis client that uses the dynamic `redis_url`.
"""
conn = RedisConnectionFactory.get_redis_connection(redis_url)
yield conn
conn.close()

Expand Down
1,168 changes: 558 additions & 610 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ cohere = { version = ">=4.44", optional = true }
mistralai = { version = ">=1.0.0", optional = true }
boto3 = { version = ">=1.34.0", optional = true }
voyageai = { version = ">=0.2.2", optional = true }
pytest-xdist = {extras = ["psutil"], version = "^3.6.1"}

[tool.poetry.extras]
openai = ["openai"]
Expand All @@ -50,7 +51,6 @@ black = ">=20.8b1"
isort = ">=5.6.4"
pylint = "3.1.0"
pytest = "8.1.1"
pytest-cov = "5.0.0"
pytest-asyncio = "0.23.6"
mypy = "1.9.0"
types-redis = "*"
Expand Down Expand Up @@ -81,8 +81,6 @@ check-lint = "scripts:check_lint"
check-mypy = "scripts:check_mypy"
test = "scripts:test"
test-verbose = "scripts:test_verbose"
test-cov = "scripts:test_cov"
cov = "scripts:cov"
test-notebooks = "scripts:test_notebooks"
build-docs = "scripts:build_docs"
serve-docs = "scripts:serve_docs"
Expand Down
1 change: 1 addition & 0 deletions redisvl/schema/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ def as_redis_field(self) -> RedisField:

class FlatVectorField(BaseField):
"Vector field with a FLAT index (brute force nearest neighbors search)"

type: str = Field(default="vector", const=True)
attrs: FlatVectorFieldAttributes

Expand Down
Loading