Add branch protection guide and PR CI workflow

Introduces .github/BRANCH_PROTECTION_GUIDE.md to document branch protection and CI requirements. Adds .github/workflows/pr-checks.yml for PR validation, including unit tests and code quality checks. Updates TESTING_QUICKSTART.md and tests/TEST_SUMMARY.md to use consistent status check notation and clarify test suite details.
This commit is contained in:
Edwin Jose 2025-10-07 04:46:54 -04:00
parent 3881c50ad5
commit d66a6284cd
4 changed files with 469 additions and 56 deletions

291
.github/BRANCH_PROTECTION_GUIDE.md vendored Normal file
View file

@ -0,0 +1,291 @@
# Branch Protection Configuration Guide
This guide explains how to configure branch protection rules for the `main` branch to ensure all tests pass before merging.
## Quick Setup
### 1. Navigate to Branch Protection Settings
1. Go to your repository on GitHub
2. Click **Settings** → **Branches**
3. Click **Add rule** or **Edit** for the `main` branch
### 2. Configure Required Settings
Enable the following options:
#### Required Status Checks
[x] **Require status checks to pass before merging**
- [x] Require branches to be up to date before merging
- Required checks:
- `Test Validation` (from pr-checks.yml)
- `Run Tests` (from tests.yml)
- `test-validation` (job name)
#### Additional Protections (Recommended)
- [x] Require a pull request before merging
- Required approvals: 1 (recommended)
- Dismiss stale reviews when new commits are pushed
- [x] Require conversation resolution before merging
- [x] Do not allow bypassing the above settings
## CI Workflows Overview
### 1. `tests.yml` - Main Test Workflow
**Triggers:**
- Push to `main` branch
- Pull requests to `main` branch
**Jobs:**
- `test`: Runs unit tests (required to pass)
- `integration-test`: Runs integration tests with OpenSearch (optional)
- `lint`: Code quality checks (optional)
- `test-summary`: Aggregates results
**Required for merge:** [x] Yes (test job must pass)
### 2. `pr-checks.yml` - PR-specific Validation
**Triggers:**
- Pull request opened/updated to `main`
**Jobs:**
- `test-validation`: Strict unit test validation
- `code-quality`: Linting and code quality
- `pr-validation`: Final validation check
**Required for merge:** [x] Yes (test-validation job must pass)
## What Tests Must Pass?
### Required [x]
- All unit tests (77+ tests)
- Runtime: ~2 seconds
- No external dependencies
### Optional [INFO]
- Integration tests (require OpenSearch)
- Linting checks
- Code quality checks
## Test Commands Run in CI
```bash
# Unit tests (REQUIRED - must pass for merge)
uv run pytest tests/ -v \
-m "not requires_opensearch and not requires_langflow" \
--cov=src \
--cov-report=xml \
--cov-fail-under=1
# Integration tests (OPTIONAL - informational)
uv run pytest tests/ -v \
-m "integration and requires_opensearch" \
--cov=src \
--cov-report=xml
```
## PR Workflow
### Contributor Flow
1. **Create feature branch**
```bash
git checkout -b feature/my-feature
```
2. **Make changes and run tests locally**
```bash
make test-unit
```
3. **Push changes**
```bash
git push origin feature/my-feature
```
4. **Create Pull Request**
- CI automatically runs
- Status checks appear on PR
5. **Review CI Results**
- [x] Green checks = ready to merge
- [FAIL] Red checks = fix issues
6. **Merge when tests pass**
- All required checks must be green
- PR can be merged to main
### Status Check Results
#### [x] Success
```
[x] Test Validation
[x] Run Tests
[x] All required tests passed
```
**Action:** PR can be merged
#### [FAIL] Failure
```
[FAIL] Test Validation
[FAIL] Some tests failed
```
**Action:** Fix failing tests and push changes
## Local Testing Before Push
Ensure tests pass locally before pushing:
```bash
# Quick check (recommended)
make test-unit
# Full test suite
make test
# With coverage
make test-coverage
# Specific tests
make test-api
make test-service
```
## Troubleshooting CI Failures
### Tests fail in CI but pass locally
1. **Check Python version**
```bash
python --version # Should be 3.13
```
2. **Ensure dependencies are in sync**
```bash
uv sync --extra dev
```
3. **Run tests in CI mode**
```bash
uv run pytest tests/ -v -m "not requires_opensearch and not requires_langflow"
```
### Permission errors in CI
- Ensure workflow has necessary permissions
- Check GitHub Actions settings
### Flaky tests
- Integration tests may be flaky (that's why they're optional)
- Unit tests should be stable
- Report flaky tests as issues
## Bypassing Branch Protection (Emergency Only)
[WARN] **Not recommended for normal workflow**
If you're a repository admin and need to bypass:
1. Go to Settings → Branches
2. Temporarily uncheck protection rules
3. Merge PR
4. **Immediately re-enable protection**
[WARN] **Always fix tests instead of bypassing!**
## Configuration Examples
### Minimal Configuration (Recommended)
```yaml
Branch Protection Rules for main:
☑ Require status checks to pass before merging
☑ Require branches to be up to date
Required checks:
- test-validation
- Run Tests
☑ Require a pull request before merging
```
### Strict Configuration (Team Environment)
```yaml
Branch Protection Rules for main:
☑ Require status checks to pass before merging
☑ Require branches to be up to date
Required checks:
- test-validation
- Run Tests
- code-quality
☑ Require a pull request before merging
Number of approvals: 2
☑ Dismiss stale reviews
☑ Require conversation resolution
☑ Require signed commits
☑ Include administrators
```
## Monitoring Test Health
### View Test Results
1. **In Pull Request:**
- Check "Checks" tab
- View detailed logs
- See test output
2. **In Actions Tab:**
- View all workflow runs
- Check historical pass rates
- Monitor performance
### Test Metrics
- **Success Rate:** Should be 100% for unit tests
- **Runtime:** ~2 seconds for unit tests
- **Coverage:** Growing toward 70%+
## FAQ
**Q: Can I merge if integration tests fail?**
A: Yes, integration tests are optional. Only unit tests are required.
**Q: How do I skip CI for a commit?**
A: You can't skip required checks. All PRs must pass tests.
**Q: What if tests are flaky?**
A: Fix the flaky tests. Unit tests should never be flaky.
**Q: Can I run CI locally?**
A: Yes, use `make test-unit` to run the same tests CI runs.
**Q: How do I add new required checks?**
A: Update branch protection settings and add job name to required checks.
## Support
- Tests failing? Check test logs in GitHub Actions
- Need help? See `tests/README.md` for testing guide
- Issues? Open a GitHub issue
## Summary
[x] **Required for merge to main:**
1. All unit tests pass (77+ tests)
2. No test failures
3. Code builds successfully
[FAIL] **Blocks merge:**
- Any unit test failure
- Build failures
- Missing required checks
**Optional:**
- Integration tests
- Linting checks
- Code coverage improvements
Enable branch protection to enforce these rules automatically!

122
.github/workflows/pr-checks.yml vendored Normal file
View file

@ -0,0 +1,122 @@
name: PR Checks
on:
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
jobs:
test-validation:
name: Test Validation
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Install dependencies
run: |
uv sync --extra dev
- name: Run unit tests with strict requirements
id: unit_tests
run: |
uv run pytest tests/ -v \
-m "not requires_opensearch and not requires_langflow" \
--cov=src \
--cov-report=term-missing \
--cov-report=xml \
--cov-fail-under=1 \
--tb=short
- name: Test Summary
if: always()
run: |
if [ "${{ steps.unit_tests.outcome }}" == "success" ]; then
echo "✅ All unit tests passed"
echo "PR is ready for review"
else
echo "❌ Tests failed"
echo "Please fix failing tests before merging"
exit 1
fi
- name: Comment PR with results
if: always() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const outcome = '${{ steps.unit_tests.outcome }}';
const icon = outcome === 'success' ? '✅' : '❌';
const status = outcome === 'success' ? 'passed' : 'failed';
const body = `## ${icon} Test Results
Unit tests ${status}!
- Python Version: 3.13
- Tests Run: Unit tests (excluding integration)
- Status: ${status}
${outcome === 'success' ? '✅ Ready for merge' : '❌ Please fix failing tests'}
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
code-quality:
name: Code Quality
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Install dependencies
run: |
uv sync --extra dev
uv pip install ruff
- name: Run ruff linter
run: |
uv run ruff check src/ tests/ --output-format=github
continue-on-error: true
pr-validation:
name: PR Validation
runs-on: ubuntu-latest
needs: [test-validation, code-quality]
if: always()
steps:
- name: Check all jobs
run: |
if [ "${{ needs.test-validation.result }}" != "success" ]; then
echo "❌ Test validation failed"
exit 1
fi
echo "✅ All PR checks passed"
echo "This PR is ready to be merged to main"

View file

@ -39,10 +39,10 @@ tests/
## Current Status ## Current Status
**77 passing unit tests** [x] **77 passing unit tests**
**~2 second runtime** [x] **~2 second runtime**
**No mocks - using real fixtures** [x] **No mocks - using real fixtures**
**Ready for CI/CD** [x] **Ready for CI/CD**
## Quick Commands ## Quick Commands

View file

@ -1,53 +1,53 @@
# OpenRAG Backend Test Suite Summary # OpenRAG Backend Test Suite Summary
## Implementation Complete ## [x] Implementation Complete
### Test Coverage Created ### Test Coverage Created
#### 1. **Utils Tests** (41 tests) #### 1. **Utils Tests** (41 tests)
- `test_embeddings.py` - Embedding dimension handling and index body creation (15 tests) - [x] `test_embeddings.py` - Embedding dimension handling and index body creation (15 tests)
- `test_hash_utils.py` - Hashing utilities for document IDs (26 tests) - [x] `test_hash_utils.py` - Hashing utilities for document IDs (26 tests)
#### 2. **API Tests** (15 tests) #### 2. **API Tests** (15 tests)
- `test_health.py` - Health check and basic API functionality (5 tests) - [x] `test_health.py` - Health check and basic API functionality (5 tests)
- `test_documents.py` - Document API endpoints (5 tests) - [x] `test_documents.py` - Document API endpoints (5 tests)
- `test_search.py` - Search API endpoints (5 tests) - [x] `test_search.py` - Search API endpoints (5 tests)
#### 3. **Service Tests** (8 tests) #### 3. **Service Tests** (8 tests)
- `test_document_service.py` - Document service operations (4 tests) - [x] `test_document_service.py` - Document service operations (4 tests)
- `test_search_service.py` - Search service operations (4 tests) - [x] `test_search_service.py` - Search service operations (4 tests)
#### 4. **Connector Tests** (8 tests) #### 4. **Connector Tests** (8 tests)
- `test_base.py` - Connector initialization and configuration (8 tests) - [x] `test_base.py` - Connector initialization and configuration (8 tests)
#### 5. **Config Tests** (5 tests) #### 5. **Config Tests** (5 tests)
- `test_settings.py` - Configuration and environment variables (5 tests) - [x] `test_settings.py` - Configuration and environment variables (5 tests)
### Test Infrastructure ### Test Infrastructure
#### Pytest Configuration #### Pytest Configuration
- `pytest.ini` - Test discovery, markers, coverage settings - [x] `pytest.ini` - Test discovery, markers, coverage settings
- `conftest.py` - Root fixtures and configuration - [x] `conftest.py` - Root fixtures and configuration
- Coverage reporting (HTML, XML, terminal) - [x] Coverage reporting (HTML, XML, terminal)
#### Fixture System (No Mocks!) #### Fixture System (No Mocks!)
- `fixtures/opensearch_fixtures.py` - Real OpenSearch test fixtures - [x] `fixtures/opensearch_fixtures.py` - Real OpenSearch test fixtures
- `fixtures/service_fixtures.py` - Service instance fixtures - [x] `fixtures/service_fixtures.py` - Service instance fixtures
- `fixtures/connector_fixtures.py` - Connector fixtures - [x] `fixtures/connector_fixtures.py` - Connector fixtures
- `fixtures/app_fixtures.py` - Application-level fixtures - [x] `fixtures/app_fixtures.py` - Application-level fixtures
#### Makefile Commands #### Makefile Commands
- `make test` - Run all tests - [x] `make test` - Run all tests
- `make test-unit` - Unit tests only - [x] `make test-unit` - Unit tests only
- `make test-integration` - Integration tests only - [x] `make test-integration` - Integration tests only
- `make test-api` - API tests - [x] `make test-api` - API tests
- `make test-service` - Service tests - [x] `make test-service` - Service tests
- `make test-connector` - Connector tests - [x] `make test-connector` - Connector tests
- `make test-coverage` - Tests with coverage report - [x] `make test-coverage` - Tests with coverage report
- `make test-verbose` - Verbose output - [x] `make test-verbose` - Verbose output
- `make test-failed` - Re-run failed tests - [x] `make test-failed` - Re-run failed tests
- `make test-quick` - Quick unit tests - [x] `make test-quick` - Quick unit tests
- `make test-specific TEST=path` - Run specific test - [x] `make test-specific TEST=path` - Run specific test
### Dependencies Added ### Dependencies Added
```toml ```toml
@ -60,16 +60,16 @@ dev = [
] ]
``` ```
## 📊 Test Results ## Test Results
``` ```
Total Tests: 97 (77 unit, 20 integration) Total Tests: 97 (77 unit, 20 integration)
Passing: 77/77 unit tests (100%) Passing: 77/77 unit tests (100%)
Runtime: ~2 seconds (unit tests) Runtime: ~2 seconds (unit tests)
Status: ALL PASSING Status: [x] ALL PASSING
``` ```
## 🎯 Test Categories ## Test Categories
Tests are organized with pytest markers: Tests are organized with pytest markers:
@ -81,7 +81,7 @@ Tests are organized with pytest markers:
- `@pytest.mark.requires_opensearch` - Requires OpenSearch - `@pytest.mark.requires_opensearch` - Requires OpenSearch
- `@pytest.mark.requires_langflow` - Requires Langflow - `@pytest.mark.requires_langflow` - Requires Langflow
## 📁 Test Structure ## Test Structure
``` ```
tests/ tests/
@ -102,7 +102,7 @@ tests/
└── app_fixtures.py └── app_fixtures.py
``` ```
## 🚀 Quick Start ## Quick Start
```bash ```bash
# Install test dependencies # Install test dependencies
@ -118,7 +118,7 @@ make test-coverage
make test-api make test-api
``` ```
## 🧪 Key Features ## Key Features
### 1. Fixture-Based Testing (No Mocks!) ### 1. Fixture-Based Testing (No Mocks!)
- Real OpenSearch clients for integration tests - Real OpenSearch clients for integration tests
@ -148,19 +148,19 @@ make test-api
- Coverage enforcement - Coverage enforcement
- Configurable markers - Configurable markers
## 📈 Coverage Goals ## Coverage Goals
Current: Growing from 1.44% (utils only) Current: Growing from 1.44% (utils only)
Target: 70%+ overall coverage Target: 70%+ overall coverage
Tested modules: Tested modules:
- utils/embeddings.py - 100% - [x] utils/embeddings.py - 100%
- utils/hash_utils.py - 88% - [x] utils/hash_utils.py - 88%
- ⏳ services/* - To be expanded - ⏳ services/* - To be expanded
- ⏳ api/* - To be expanded - ⏳ api/* - To be expanded
- ⏳ connectors/* - To be expanded - ⏳ connectors/* - To be expanded
## 🔧 Integration Tests ## Integration Tests
Integration tests require external services: Integration tests require external services:
@ -175,7 +175,7 @@ make test-integration
pytest -m "not requires_opensearch and not requires_langflow" pytest -m "not requires_opensearch and not requires_langflow"
``` ```
## 📝 Sample Test ## Sample Test
```python ```python
import pytest import pytest
@ -187,19 +187,19 @@ class TestEmbeddingDimensions:
assert get_embedding_dimensions("text-embedding-ada-002") > 0 assert get_embedding_dimensions("text-embedding-ada-002") > 0
``` ```
## 🎓 Best Practices Implemented ## Best Practices Implemented
1. Use fixtures instead of mocks 1. [x] Use fixtures instead of mocks
2. Organize tests by category with markers 2. [x] Organize tests by category with markers
3. Keep unit tests fast 3. [x] Keep unit tests fast
4. Proper resource cleanup 4. [x] Proper resource cleanup
5. Test one thing per test 5. [x] Test one thing per test
6. Descriptive test names 6. [x] Descriptive test names
7. Follow AAA pattern (Arrange, Act, Assert) 7. [x] Follow AAA pattern (Arrange, Act, Assert)
8. Independent tests 8. [x] Independent tests
9. Clear documentation 9. [x] Clear documentation
## 🔄 Next Steps ## Next Steps
To expand test coverage: To expand test coverage:
@ -210,13 +210,13 @@ To expand test coverage:
5. Add flow management tests 5. Add flow management tests
6. Increase coverage to 70%+ 6. Increase coverage to 70%+
## 📚 Documentation ## Documentation
- `tests/README.md` - Comprehensive testing guide - `tests/README.md` - Comprehensive testing guide
- `pytest.ini` - Configuration reference - `pytest.ini` - Configuration reference
- `Makefile` - Available commands - `Makefile` - Available commands
## Highlights ## Highlights
- **No mocks used** - Real fixtures for better integration testing - **No mocks used** - Real fixtures for better integration testing
- **77 passing tests** - All unit tests green - **77 passing tests** - All unit tests green