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
42 changes: 42 additions & 0 deletions .github/workflows/enterprise-integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Run Enterprise Integration Tests

on:
push:
branches:
- main
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ (github.head_ref && github.ref) || github.run_id }}
cancel-in-progress: true

jobs:
test-enterprise-integration:
name: Enterprise Python Integration Tests
runs-on: ubuntu-24.04
strategy:
matrix:
python-version: ["3.12"]
steps:
- uses: actions/checkout@v6
- name: Install poetry via pipx
run: pipx install poetry
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "poetry"
- name: Install Python dependencies using Poetry
working-directory: ./enterprise
run: poetry install --with dev,test
- name: Run Integration Tests
# Use base working directory for coverage paths to line up.
run: PYTHONPATH=".:$PYTHONPATH" poetry run --project=enterprise pytest --forked -n auto -s -p no:ddtrace -p no:ddtrace.pytest_bdd -p no:ddtrace.pytest_benchmark ./enterprise/tests/integration --cov=enterprise --cov-branch
env:
COVERAGE_FILE: ".coverage.enterprise.integration.${{ matrix.python-version }}"
- name: Store coverage file
uses: actions/upload-artifact@v7
with:
name: coverage-enterprise-integration
path: ".coverage.enterprise.integration.${{ matrix.python-version }}"
include-hidden-files: true
3 changes: 3 additions & 0 deletions enterprise/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ lint.pydocstyle.convention = "google"
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
markers = [
"integration: mark test as requiring a real database (deselect with '-m not integration')",
]

[tool.coverage.run]
relative_files = true
Expand Down
Empty file.
99 changes: 99 additions & 0 deletions enterprise/tests/integration/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import os

import pytest
from sqlalchemy import create_engine
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import sessionmaker

# Import all models so their tables are created.
from storage.api_key import ApiKey # noqa: F401
from storage.base import Base
from storage.billing_session import BillingSession # noqa: F401
from storage.conversation_work import ConversationWork # noqa: F401
from storage.device_code import DeviceCode # noqa: F401
from storage.feedback import Feedback # noqa: F401
from storage.github_app_installation import GithubAppInstallation # noqa: F401
from storage.org import Org # noqa: F401
from storage.org_git_claim import OrgGitClaim # noqa: F401
from storage.org_invitation import OrgInvitation # noqa: F401
from storage.org_member import OrgMember # noqa: F401
from storage.role import Role # noqa: F401
from storage.slack_conversation import SlackConversation # noqa: F401
from storage.stored_conversation_metadata import (
StoredConversationMetadata, # noqa: F401
)
from storage.stored_conversation_metadata_saas import ( # noqa: F401
StoredConversationMetadataSaas,
)
from storage.stored_offline_token import StoredOfflineToken # noqa: F401
from storage.stripe_customer import StripeCustomer # noqa: F401
from storage.user import User # noqa: F401
from storage.user_settings import UserSettings # noqa: F401


def pytest_collection_modifyitems(config, items):
for item in items:
item.add_marker(pytest.mark.integration)


@pytest.fixture(autouse=True)
def allow_short_context_windows():
old = os.environ.get('ALLOW_SHORT_CONTEXT_WINDOWS')
os.environ['ALLOW_SHORT_CONTEXT_WINDOWS'] = 'true'
try:
yield
finally:
if old is None:
os.environ.pop('ALLOW_SHORT_CONTEXT_WINDOWS', None)
else:
os.environ['ALLOW_SHORT_CONTEXT_WINDOWS'] = old


@pytest.fixture(scope='function')
def db_path(tmp_path):
"""Create a unique temp file path for each test."""
return str(tmp_path / 'test.db')


@pytest.fixture
def engine(db_path):
"""Create a sync engine with tables using file-based DB."""
engine = create_engine(
f'sqlite:///{db_path}', connect_args={'check_same_thread': False}
)
Base.metadata.create_all(engine)
try:
yield engine
finally:
engine.dispose()


@pytest.fixture
def session_maker(engine):
return sessionmaker(bind=engine)


@pytest.fixture
def async_engine(engine, db_path):
"""Create an async engine using the SAME file-based database.

Depends on engine so tables are already created before async tests run.
"""
ae = create_async_engine(
f'sqlite+aiosqlite:///{db_path}',
connect_args={'check_same_thread': False},
)
try:
yield ae
finally:
ae.dispose()


@pytest.fixture
async def async_session_maker(async_engine):
"""Create an async session maker bound to the async engine."""
return async_sessionmaker(
bind=async_engine,
class_=AsyncSession,
expire_on_commit=False,
)
Loading